当服务一个客户请求可能花费较长时间时,我们并不希望整个服务器被单个客户长期占用,而是希望同时服务多个客户
unix中编写并发服务器程序最简单的方法就是fork一个子进程来服务每个客户
======================
典型的并发服务器程序轮廓
=====================
pid_t pid; int listenfd,connfd; listenfd = socket(...); bind(listenfd,...); for(;;) { connfd = accept(listenfd,...); if((pid = fork()) == 0) { close(listenfd);//子进程关闭listening socket doit(connfd);//处理请求 close(connfd);//客户执行完毕,关闭已经连接的socket exit(0);//子进程结束 } close(connfd);//父进程关闭已经连接的socket }
当一个连接i建立时,accpt返回,服务器接着调用fork,然后由子进程服务客户,父进程则等待另一个连接
既然新的客户由子进程提供服务,父进程就关闭已连接套接字
对一个TCP套接字调用close会导致发送一个FIN,随后是正常的TCP连接终止序列
但为什么父进程调用close没有终止它与客户的连接呢?
我们必须知道每个文件或套接字都有一个引用计数,引用计数在文件表项中记录,他是当前打开着的引用该文件或套接字的个数
socket返回后与listenfd关联的文件表项的引用记数值为1
accept返回后与connfd关联的文件表项的引用计数为1
然而fork返回后,这2个描述符就在父进程与子进程间共享(被复制一份到子进程),因此与这2个套接字相关连的文件表项各自的访问计数值均为2
这么一来,当父进程关闭connfd时,它只是把相应的引用计数值从2减为1
该套接字真正的清理和资源释放需要等到其引用计数值达到0时才发生