并发服务器程序的轮廓
-
pid_t pid;
-
int listenfd,connfd;
-
-
listenfd = socket(AF_INET,SOCK_STREAM,0);
-
-
bind(listenfd,...);
-
-
listen(listenfd, LISTENQ);
-
-
for(;;)
-
{
-
connfd=accept(listenfd,...);
-
pid=fork();
-
-
if(pid==0) {
-
close(listenfd);
-
doit(connfd);
-
close(connfd);
-
exit(0);
-
}
-
close(connfd);
-
}
每一个socket描述符都有对应的引用计数,该计数存在文件表中。上面程序中打开了listenfd和connfd,引用计数分别为1和1,在fork()以后,子进程复制了父进程的socket描述符,所以listenfd和connfd的引用计数都变成了2。此时在子进程中关闭listenfd(close(listenfd)),在父进程中关闭close(connfd).这个就保证了子进程处理与客户的连接,父进程负责在监听套接字listenfd再次调用accept来接收客户的下一个连接。
如下图所示:
可能看到这,大家有疑问了? 为啥父进程调用close后没有发送FIN报文来结束连接,而子进程仍然可以用connfd进行数据处理呢?
其实,从上面分析和图示可以看出socket描述符是有引用计数的,只有当引用计数为0的时候,close才会发送FIN报文,这就解释了子进程仍然可以用connfd进行数据处理了,子进程处理完后再次调用close,此时引用计数从1变为0,最后发送FIN报文结束connfd连接。
而对于listenfd,只有在子进程中进行了close,父进程中一直保留着引用计数为1,所以父进程通过for循环可以持续accept新连接。
阅读(1203) | 评论(0) | 转发(0) |