博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Concurrent Server using TCP

Posted on 2011-04-11 10:45  天地玄黄  阅读(554)  评论(0编辑  收藏  举报

     这里简要介绍一下多个Client 同时连接Server 时的处理方法:

     1、Server 端调用socket(), bind(), listen()函数建立起自己的socket,并且调用accept()函数等待接收来自Client 的信息。此时的accept() 函数处于blocked 状态。

          · socket() 函数的作用是建造一个可以使用的网络连接的基础工具。就像我们想要到电话,就需要有一台电话机。这个函数就相当于构造一台电话机。

          · bind() 函数的作用相当于为我们的电话机分配一个电话号码。在网络中就是分配IP地址和Port端口。使得其他人可以通过这个号码给我们打电话。

          · listen() 函数的作用是把我们建立的这个socket变成一个passive socket,把socket state从CLOSED 变为LISTEN。相当于把我们的电话编程只能接不能打的电话。另外,它还分配一个最大的连接数,即在一个比较短的时间段内最多可以有多少Client 连接到我们这个Server 上。bind() 函数和listen() 函数都要使用从socket() 函数中返回的file descriptor (sockfd) 来对这个socket 进行操作。listen() 函数自己返回 listenfd,表明这个 socket 已经变成可以接听的了。

          · accept() 函数的功能就是接受一个来自Client 的连接请求,就像我们的电话响了,我们接听电话一样。在Server 调用 accept() 函数之后,它就处于blocked 状态,等待Client 端使用connet() 来进行连接。连接好之后,accept() 函数返回 connfd,表明这个 socket 已经连接起来了,即他们正在通话。

     2、Client 端调用socket() 函数也构建起自己的一个电话机,用来给别人打电话。之后就调用connet() 函数跟别人打电话。

          这两个过程可以参看图4.1:

image

     3、在Client 刚刚调用connet() 函数连接到 Server 上的时候,accept() 函数还没有返回,他们的连接是靠 listenfd 来进行的。如图4.14:

image

     4、之后Server 端的accept() 函数返回,这个TCP连接就是和 connfd 连在一起了,如图4.15:

image

     5、由于Server 端需要处理很多Client,所以它调用fork() 函数开启一个子进程来对当前的Client 进行通话。子进程和父进程除了pid不一样之外,其他的东西基本一样。如图4.16:

image

     6、之后,子进程专门进行对这个Client 的处理,而父进程则依旧等待其他连接,他们各自把不需要的socket descriptor 关掉,如图4.17所示:

image

           这里有一点要注意,当父进程和子进程使用close() 函数关闭他们各自的socket 的时候,并不会出发TCP进行FIN操作。这是因为,对于每一个socket descriptor,在Unix的file table中都有对应的 reference count,只有当这个count 值为0的时候,close() 函数才会出发FIN操作。在图4.16中,listenfd 和 connfd 的 reference count 都为2,他们各自调用close() 函数,只会把这两个的reference count 减为1而已,不会进行其他操作。如果想强制进行FIN操作,可以调用shutdown() 函数。

     7、之后,Server 就可以继续调用accept() 函数,等待其他Client 的连接了。