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版本或者双线程版本