现在的位置: 首页 > 综合 > 正文

UnixSocketV1Chap27ServerClientProgrammDesign

2013年11月08日 ⁄ 综合 ⁄ 共 2165字 ⁄ 字号 评论关闭

27章 服务器和客户端程序设计方式

 

一、       并发服务器程序,每个客户请求一个进程

定义:调用fork为每个客户端产生一个子进程来处理客户的请求。缺陷是进程的子进程数的限制以及fork消耗的资源。

伪代码流程:

While(1)

{

Fd = Accept

If( 0 ==(pid= fork) )

{

      Read

      Write

     Exit(0)

}

Close(fd)

}

特点:

1.      类似HTTP请求,一个请求对应着一个socket以及一个子进程

2.      close(fd)也可以不执行,保持连接,下次再有数据过来,则又fork个子进程来进行处理

 

二、       TCP预先派生子进程,accept无上锁保护

定义:在服务器程序启动时,预先生成多个子进程,当一个客户请求达到时,为其分配一个子进程来进行处理。

伪代码流程:

For(nchildNum)

{

   If(0 ==(pid=fork) )

   {

     While(1)

     {

        Fd = Accept

        Read

        Write

        Close(fd)

     }

}

Return pid;

}

特点:

1、 每个子进程都具备accept、read、write的操作,不存在服务器程序为每个客户请求分配子进程的操作

2、 需要预估客户的总请求数,也就是子进程的数量

3、 管理子进程的运行情况,当空闲子进程数量小于一个阈值时,可以继续fork; 当空闲子进程数量大于一个阈值时,可以close。

4、 如果再accept之前通过select来监听,则会出现select冲突,当有新连接过来时,内核会通知所有监听此socket的线程,导致select冲突。

 

 

三、       TCP预先派生子进程,accept有上锁保护

基本流程与二相同,使用MUTEX来保护accept操作,注意与多线程中MUTEX的使用有差异:

1、 MUTEX变量必须attach到共享内存中,供多进程使用

2、 必须通知线程库,MUTEX变量是在进程间使用的(PTHREAD_PROCESS_SHARED)

 

四、       TCP预先派生子进程,传递描述字

定义:在父进程中accept,然后通过管道将socket描述字传递给子进程,取一个空闲子进程,处理客户请求

伪代码流程:

略(复杂)

特点:

1、 需要维护一个结构体数组来保存所有子进程的状态,包括空闲状态、传递的套接字信息等

2、 父进程和子进程之间通过管道来传递在父进程accept生成的套接字描述字

3、 由于在取空闲子进程时,始终是从子进程数组的第一个元素开始遍历,因此,各个子进程被调用的概率不一样,前面的比后面的概率高很多

 

五、            并发服务器,每个客户请求一个线程

六、            预先派生子线程,各个子线程分别accept

七、            预先派生子线程,主线程统一accept(无需管道)

八、            服务器程序设计小结

1、 负载较轻时,并发服务器就够了

2、 预先分配子进程(线程),可以减少进程控制CPU时间,大约减少10倍以上。并且编码也不复杂,不过对于实时系统而言,还必须监视空闲子进程数量,并随所服务客户数的动态变化而增加或减少这个数目

3、 某些实现允许多个进程或线程阻塞在accept调用上,而另外一些实现,必须使用同步锁来保护accept

4、 由于select冲突的存在,让所有子进程或线程阻塞在同一监听套接口的accept调用上要比让他们阻塞在select调用上更为可取。

 

 

九、       停等方式

定义:简单的循环读写

伪代码流程:

While(get)

{

   Write

   Read

   Put

}

特点:

1、 当等待用户输入时,无法监控网络事件

2、 停等模式,批处理效率极低

 

十、       Select+阻塞IO

定义:通过select来同时监视用户输入和网路事件

伪代码流程:

While(1)

{

   Select(stdin, fd)

   If(fd)

     Read

   If(stdin)

     Fgets

  write

}

 

十一、select+非阻塞IO

同十,只需判断返回值

 

十二、fork版本

伪代码流程:

 

If( 0 == fork )

{

   Whiel(Read)

      Fputs(stdout)

}

while( fgets)

  write

 

十三、线程版本

同fork版本

 

十四、客户端程序设计总结

1、 停等模式效率低,通过select同时监控用户输入和网络事件得到改进,使用shutdown来关闭客户到服务器的写socket,来实现批输入操作。

2、 双进程和双线程版本中,一个处理从服务器到客户的数据,一个处理从客户到服务器的数据

3、 消耗时间,测试从客户到服务拷贝2000行

(1)      停等方式,345.0秒

(2)      Select+阻塞,12.3秒

(3)      Select+非阻塞,6.9秒

(4)      Fork双进程,8.7秒

(5)      双线程,8.5秒

4、select+非阻塞是最快的,几乎是select+阻塞的两倍。虽然fork双进程比select+非阻塞要慢,但代码简单得多,因此推荐fork版本或者双线程版本

抱歉!评论已关闭.