http://www.cnblogs.com/wolflion/archive/2011/07/13/2539138.html
迭代服务器比较原始,它的原型可以描述成:
while(1)
{
new_fd = 服务器accept客户端的连接(new_fd = accept(listenfd, XX, XX))
逻辑处理
在这个new_fd上给客户端发送消息
关闭new_fd
}
也就是说,这个进程是一个一个处理各个客户端发来的连接的,比如一个客户端发来一个连接,那么只要它还没有完成自己的任务,那么它就一直会占用服务器的进程直到处理完毕后服务器关闭掉这个socket。
并发服务器是最经常用的:
1 while(1)
2 {
3 new_fd = 服务器accept客户端的连接
4 if(是子进程)
5 {
6 首先关闭掉监听fd // 因为子进程并不需要监听,它只负责处理逻辑并发消息给客户端
7 处理逻辑发送消息
8 关闭new_fd
9 关闭进程
10 }
11 关闭new_fd
12 }
这样每来一个客户端,服务器就克隆一个自己去处理请求,这样主进程就一直处于监听状态而不会被阻塞
额,我想讲的重点不是这里,重点是代码第12行!
1。千万不要以为fork出来一个子进程就产生了2个新的socket描述符,实际上子进程和父进程是共享linten_fd和new_fd的,当父进程关闭new_fd的时候(代码第12行)它只是把这个new_fd的访问计数值减了1而已,由于访问计数值还 > 0(因为还有客户端的new_fd连着呢),所以它并没有断开和客户端的连接。
2。如果我们不写第12行会有什么后果,第一,因为可分配的socket描述符是有限的,如果分配了以后不释放,也就是不能回收再利用,也就是总有描述符耗尽的一天。第二,本来把和客户端连接的任务交给子进程以后父进程就可以继续监听并accept下个连接了,但如果父进程不关闭自己跟客户的连接,意思就是这个连接居然永远存在!相当于每来一个客户这个父进程就连一个客户并且连接不断,你应该知道后果了吧。