TCP 端口监听队列原理

近期需要实现一个TCP线程池服务,该服务需要能够在同一个端口上实现 TCP 常规服务、HTTP请求服务、SOAP WebService 服务,为了测试 ACE 的线程池启动后,如果所有线程都在忙,客户端的连接是否还能够建立,特实现了一个简单的测试程序,如下:

ACE_TP_TEST

启动程序,该程序建立一个包含四个线程的线程池提供 TCP 服务,在 80 端口上进行监听,在客户端使用 TELNET 来进行测试,首先启动四个客户端,并且输入一个字母,让服务器的四个线程都进行繁忙状态,然后在启动一个客户端,依然能够进行连接,想起 TCP 监听端口在有连接请求过来时是有一个队列进行缓冲的,该值默认是 5,所以在启动五个客户端,这样4个在繁忙,五个进入了缓冲队列,最后一个应该连接不上了吧?结果发现启动了几十个客户端全部都连上了,此时服务器的线程池都在“繁忙”中,主线程在等待线程池结束,那么是谁接受了客户端的连接?郁闷不解中.......

查看 ACE 的源代码,发现在建立 TCP 端口监听时,对缓冲队列的大小设置是通过宏 ACE_DEFAULT_BACKLOG 来指定的,该宏在 Windows 上使用系统定义的 SOMAXCONN ,(在其他系统上使用默认值 5) , 而 SOMAXCONN 的定义是 0x7fffffff , (当然实际上不可能有这么多的连接到达,即使有缓冲队列也不可能容纳的下,因为几乎不可能有那么大的内存来做缓冲)查阅 MSDN 说使用该值,系统将尽可能的缓冲所有的客户端连接请求,就是说在 Windows 上,只要服务器系统能力允许,几十服务器上的程序繁忙,客户端的连接请求几乎都能够被系统缓存下来,客户端不会发生连接失败的情况;

最后在 TCP/IP 详解一书中的 194 页找到了相关的描述,在建立 TCP 的端口监听时可以指定一个连接的缓冲队列,该队列的长度上限在 Unix 和早期的 Windows 上默认实现都是 5 个,在新版本的 Windows 中该队列的上限系统不再做限制;

当客户端发起连接时,首先是 TCP 接受了该连接,然后应用程序接受该连接,如果应用程序忙没有即时接受连接(即将该连接从 TCP 接受的连接队列中移走)那么只有在队列满后 TCP 将不再接受客户端的连接,所以此时服务器程序即使处于繁忙中,客户端的连接因为 TCP 接受了,虽然服务器程序没有接受该连接,但是客户端的表现是连接已经建立,但是发送任何内容给服务器都没有反映(因为服务器程序没有接受该连接);

呵呵,原来如此......

posted @ 2009-03-04 09:10  王志科  阅读(7779)  评论(0编辑  收藏  举报