zoukankan      html  css  js  c++  java
  • 服务器编程模型

     

    最近看了UNP,这是对服务器编程模型的笔记

     

    1.简单服务器模型(迭代)

      服务器进程接受连接,处理请求,然后等待下一个连接。从进程控制
    的角度来说这种模型是最快的,因为没有进程间的切换,但是客户需要等待
    在listen中等待服务器accept。

     
     

    2.多进程模型

      服务器进程接受连接,fork一个子进程为客户服务,然后等待下一个连接。
    多进程模型适用于单个客户服务需要消耗较多的 CPU 资源,例如需要进行大
    规模或长时间的数据运算或文件访问。多进程模型具有较好的安全性。在实现中
    需要注意
      1.监听套接口和链接套接口的关闭时机;
      2.及时处理已经结束的子进程(信号处理);
      3.被中断的系统调用的恢复(EINT);
      这种实现模式占用的CPU时间是最多的(不包括由intend激活的服务器-fork+exec),
    因为对每个客户都单独fork。

     

    3.预先分配进程,子进程同时accept

      (Apatch 1.1)预先分配一批子进程,同时阻塞在listened套接口上等待客户的到来。
    描述符只是某个数组的下标,用于引用一个file结构。fork复制描述符,
    并且将file中的 引用计数加1. 所以子进程中描述符所引用的file结构
    与父进程中描述符引用的file结构一致。(注意如果使用SVR4内核那么系统
    提供的accept是哭喊数,将不支持同时阻塞在同一个套接口上---解决方法是
    在各个process调用accept前竞争锁资源-----这里又有两种选择:1.文件锁
    2.线程互斥锁+进程间共享内存{pthreead_mutext也可以用于进程互斥})

    如图:

      这种模式下N个子进程都调用accept并被内核置入睡眠状态(tsleep).
    也就是说这N个进程都睡眠在同一个file结构的等待通道上(wait channel).
    当某个客户到来时,N个进程同时被唤醒(惊群),但是只有一个进程能获得链接,
    其它进程继续投入睡眠. 详细情况可以参考TCPv2 15.10节对tsleep函数的说明

      惊群(所有process被唤醒进行调度,但是只有1个成功返回,其它继续tsleep)
    可能导致性能的下降。

    4.预先分配进程,父进程accept

      为了避免惊群以及同时accept在同一个监听套接口.可以选择在父进程中accept获得
    链接套接口后讲链接套接口传给一个空闲进程。但是这样父进程就得跟踪各个子进程的状态
    以便下发任务。

      可以选择在孩儿们和父进程之间建立管道进行通信,老爸使用select同时监视listenfd和这N个
    管道的fd。

      这里的流管道有两个作用:
      1.父进程将链接套接口传给子进程.
      2.子进程管理:子进程处理完一个链接后写一下管道,导致父进程中的select等待的对应
    描述符可读,父进程就知道该儿子闲了(read>0) 或者这个儿子挂了(read=0);

      这种模式并不比靠锁进行同步(模式3)的方式快。

    5.TCP 每个客户一个线程

      每次accept返回connfd后调用pthread_create(&tid, NULL, &doit, (void *)connfd)
    创建一个新线程(执行doit),在doit中detach不用主进程等自己,doit执行完后关闭connfd。

      优势:线程调度轻于进程; connfd共享,不用传递。比前面的几个进程版本都快。

      注意线程安全

    6.TCP 预先分配线程池,同时accept

      之前发现预先分配进程比每次单独分配快,那么我们现在搞一个线程池会有优化么?

      思路:是预先创建N个thread,并循环的 用互斥锁互斥调用accept,处理链接,等待下一个链接。
      如果内核支持同时多个accept阻塞在同一个fd上,可以减少加锁的代价,但是会产生惊群的消耗。

       结果:很快

    7.TCP 预先分配线程池,主线程accept

      那么现在的问题就变成了怎么把获得的connfd交给子线程了,也就是一个典型的生产-消费问题。

    使用
      1. pthread_mutext : 竞争访问connfdseq.
      2. pthread_cond_signal : 如果connfdseq空等待资源并释放mutext
    可以解决。

      结果:比6要慢一些

    8.TCP 单进程, 使用select

      即便是使用线程减少了调度的代价,但是代价还是有的,而且同步也需要机器的资源。
    并且每个线程也要占用一定的资源来保存自己的一些信息(3M?)。既然大多数调用都是阻塞在
    了IO上,那为什么我们不把这些IO操作交给内核管理呢? 这不久是select,pool的作用么?

      将listenfd和connfd都交给select,返回是判断如果是listenfd好了,那么调用accept得到
    connfd并且将其也放入select; 如果是某个connfd好了那就进行读写对客户进行服务。

      最近在看的web.py 以及 torrando都是使用这种方式,并且有较高的效率(有epool等异步io的帮助)。


     
     
     
     
  • 相关阅读:
    《Mathematical Olympiad——组合数学》——染色问题
    《啊哈算法》——栈、队列、链表
    《Mathematical Olympiad——组合数学》——抽屉原理
    2749: [HAOI2012]外星人
    bzoj4241: 历史研究
    bzoj3210: 花神的浇花集会
    bzoj4998: 星球联盟
    bzoj2728: [HNOI2012]与非
    bzoj2669: [cqoi2012]局部极小值
    bzoj5441: [Ceoi2018]Cloud computing
  • 原文地址:https://www.cnblogs.com/tangr206/p/3081492.html
Copyright © 2011-2022 走看看