如何判斷一個tcp空連接(50分)

  • 主题发起人 主题发起人 melice
  • 开始时间 开始时间
to 陈一蛟:
1.楼主并不是问是不是需要每个连接开一个线程,只是我说如果用ServerSocket就一定会,
ServerSocket就是这样。
2.楼主没有问使用完成端口的细节。
3.楼主用的是ServerSocket,没有用select IO模型,他认为ServerSocket下无法捕捉到
断开。
 
他认为ServerSocket下无法捕捉到断开是正确的,不是所有的断开都可以抓住的,
事实如此。
 
事实并不如此。
MIDAS中的SocketConnection就是使用的ServerSocket,2001年我对它进行过充分细致的研
究和测试。它使用了线程池技术,根据线程池中只留10个线程来判断,SocketConnection
最好不要超过10个连接。在10个连接的时候,无论以何种方式段开,SocketConnection都
可以检测到断开。不过检测的方法是通过设置Socket接收超时并用“读取数据长度为0”作
为依据,并没有使用FD_CLOSE事件或消息。但这并不是说FD_CLOSE不能捕捉断开,而是没
有必要。因为在大多数情况下,Socket服务器是处于“读”状态的,另外再单独检测
FD_CLOSE事件实属没有必要。
如果连接数较多的情况(例如1000个连接)却是另外一番情景。ServerSocket根本无法承受
如此的线程压力,很多连接根本处于不稳定状态,有些连接过程并没有完成。因为连接过
程需要服务器和客户端两端发送和接收好几次数据(你用原始套接字去截获看看就明白了)
才能完成TCP的连接过程。事实上这些连接还处在Accept后到可以接收、发送用户数据之
间。如果系统握手还没有完成的时候,你插入用户数据,连接当然会马上断开。
 
再看看楼主的问题:
>一個長時間沒有通訊的連接,經常會因為某種原因斷開了,但是並不一定會觸發連接斷開,
>這種空連接怎麼判斷出來並斷掉.
触发肯定是可以触发,主要是看你怎么捕获。并不是有触发就一定能捕获到。如果你用
ServerSocket作为服务端组件,我建议:
1.不要超过20个连接或者至多不要超过100个连接。
2.重载线程类,在线程中捕获断开事件,一种方法是先设置接收超时,然后再调用阻塞
函数Recv。如果Recv异常返回说明已经断开。另一种方法是在线程中只等待事件,在有读
事件发生的时候才去调用阻塞函数Recv。
任何时候都不要用Timer。即使非要用也只能通过在等待函数中设置超时或者设置Socket
操作超时来使用。没有人能够肯定一次Timer触发不会与线程中的操作发生冲突。
 
事实并不如此。
MIDAS中的SocketConnection就是使用的ServerSocket,2001年我对它进行过充分细致的研
究和测试。它使用了线程池技术,根据线程池中只留10个线程来判断,SocketConnection
最好不要超过10个连接。

》》》SocketConnection 使用的是 ClientSocket; 我想你说的应该是 scktsrvr.exe 吧

在10个连接的时候,无论以何种方式段开,SocketConnection都
可以检测到断开。不过检测的方法是通过设置Socket接收超时并用“读取数据长度为0”作
为依据,并没有使用FD_CLOSE事件或消息。但这并不是说FD_CLOSE不能捕捉断开,而是没
有必要。
『因为在大多数情况下,Socket服务器是处于“读”状态的,另外再单独检测
FD_CLOSE事件实属没有必要。』

》》》这是 TSocketTransport.Receive 方法设计的一个很不合理的地方,在没有用户请求发生而处在“读”状态是非常不合理的,而且也是引起 MIDAS 在 Internet 不稳定的原因所在。在有些异常状态下,服务器在客户端断开后,并不会触发断开连接操作,因为其异常也引起服务器异常,这个线程将一直无法使用,直到重起(可能也许还会有其它因素)。


如果连接数较多的情况(例如1000个连接)却是另外一番情景。ServerSocket根本无法承受
如此的线程压力,很多连接根本处于不稳定状态,有些连接过程并没有完成。因为连接过
程需要服务器和客户端两端发送和接收好几次数据(你用原始套接字去截获看看就明白了)
才能完成TCP的连接过程。事实上这些连接还处在Accept后到可以接收、发送用户数据之
间。如果系统握手还没有完成的时候,你插入用户数据,连接当然会马上断开。

》》》实际上 ServerSocket 是可以负载 1000多个线程,因为线程的却和切换代价不是很大,但是 scktsrvr.exe 却不能(很难)负载这么大的压力,因为它是采用啦内核同步的方式,它采用啦 waitFor... 和 Event 等内核函数,这些内核同步切换会花费大量的 CPU 周期,所以 scktsrvr.exe 是很难负载大量并发请求;
其实我们在处理并发请求时是完全可以做等待机制,这也是我开 10 个线程的线程池可以在一分钟处理几万个并发请求的原因,估计完成端口也是类似机制。


再看看楼主的问题:
>一個長時間沒有通訊的連接,經常會因為某種原因斷開了,但是並不一定會觸發連接斷開,
>這種空連接怎麼判斷出來並斷掉.
触发肯定是可以触发,主要是看你怎么捕获。并不是有触发就一定能捕获到。如果你用
ServerSocket作为服务端组件,我建议:
1.不要超过20个连接或者至多不要超过100个连接。
2.重载线程类,在线程中捕获断开事件,一种方法是先设置接收超时,然后再调用阻塞
函数Recv。如果Recv异常返回说明已经断开。另一种方法是在线程中只等待事件,在有读
事件发生的时候才去调用阻塞函数Recv。
任何时候都不要用Timer。即使非要用也只能通过在等待函数中设置超时或者设置Socket
操作超时来使用。没有人能够肯定一次Timer触发不会与线程中的操作发生冲突。

》》》说得很对!!!,还有在重载线程中,要记得在ClientThread.Execute 完成时把 Socket := -1,否则会引起Socket缓存溢出错误,错误号好像是:10055 和 10048 吧


 
不好意思,我改造过的MIDAS没有scktsrvr.exe这个东西,我把它做到应用服务器中了。所
以我仍然把它叫SocketConnection。不过我要请教:1000多个线程你用什么来同步?你如何
用10个线程来等待1000个连接?
另外,客户端不一定非得用线程吧?我的客户端就不用线程,而是在消息循环中等待Socket
消息或事件。你想想,如果我想在一台机器上连接1000个服务器岂不是要开1000个线程?
 

我用 10 个线程来响应大量并发,其中最重要的就是处理完成后我就会断开客户端连接,还有在 Listen 中Socket 的队列也设定为几百个,所以即使在没有空于线程来响应用户请求,系统也会维护连接等待请求, 在有空闲线程时就马上响应客户请求,这个里面是才用户态的并发处理,所以现场切换性能会很好,CPU 占用率也会很小,另外我在我的架构里面解决啦空连接判断处理,也就是说如果客户连接只是一个连接,那我就会主动把把这个连接给断开。

 
陈一蛟的办法如果我没有猜错,应该是无状态的,
也就是说处理完了用户请求就断开连接...所以几个线程就可以处理大量连接的请求.
 
处理完就断开?如果客户有登录记录,是不是下次连接还要登录?对于不需登录的TCP服务
这样处理可以,但绝大多数情况下是需要登录的。例如ftp协议。
 


我这里说的是服务器引擎,对于 FTP 或者其它应用那些是应用层的问题,那只是一个处理策略的问题,不难解决的。
张无忌老兄说的很对;现在企业级的服务器系统都是使用的无状态处理,如果在一个系统中使用长连接,或者说有状态处理方式那是根本就不能应付大规模并发请求的,例如:COM+、EJB 的 Application都是无状态处理。


 
楼上的讨论让我受益非浅。:》
无状态连接的模式不适合需要认证的服务,也不是我们讨论的范围,还是回到主题上来。
 
无状态连接可以支持认证,只是他的状态有2种,通过认证以后就是无状态了
 
无状态用户管理当然简单。我是说如果服务需要权限认证呢?每处理一次业务都必须进行
权限认证吗?如何记录哪些用户在线,哪些用户离线?
 
>>无状态连接可以支持认证,只是他的状态有2种,通过认证以后就是无状态了
完全没有道理。什么时候有的两种状态?什么时候又是无状态?只要服务器记录“客户已登
录”或“客户未登录”就说明不是无状态连接。
 
to barton: 服务器端的线程并不需要和socket连接一一对应,一个线程管理数十个链接是没有问题的。至于一个serversocket可以链接的上限,如果一直保持数据通讯的话,2k个链接是完全正常的。 大型网络游戏传奇和金庸的服务器端,使用的就是一个serversocket,承受的玩家数量在2k时并没有任何问题。
 
天啊 。 看着你们长篇大论真是好累啊。

贴主: 要想完成几百个连接以上服务器, 必须抛弃线程模型, 使用 EVENT 和IO重叠模型
我这里曾经有过具体测试, 阻塞的多线程模型服务器最多跑到过600多连接。
服务器 : P4. 2.4G 两个 双路XEON 内存 2G

Barton : 你的话实在太多乐。 我只是看到乐你最后的一句话, 你不相信 CLIENT 端断开
后服务器受不到消息这种事吗? 事实上服务器如果和客户端建立起一个空连接后
却是是没有什么流量的。 正常情况下, 客户鸡A 和服务器B 建立连接后,
错漏包重发是通过TCP 协议自动完成的, A客户如果想断开连接, 也需要
通过CLOSESOCKET 告诉TCP 缓冲区将此信息发到服务器, 然后TCP协议会千方百计
的将此消息发到服务器, 如果数据包在网络上因故丢失,而客户机因某种原因DOWN
掉了的话, 这个消息就到不了服务器了。
如果 A 和 B 建立了连接, A 突然断电, 甚至这个消息都到不了TCP 缓冲区,B
机当然不知道A 已经完了。


所以确实是需要轮询的


陈一娇兄弟的帖子也太长了,该下班了,不看了。
 
to melice:
你说的TServerSocket可以处理2000个连接,应该是非组塞模式,
但是消息模式的效率不高,和消息队列混合使I/O处理的效率大
大降低,MS测试到了1000个连接以后就不行了,速度下降很快.
基本就不接受新的连接
 
to barton:
无状态也要检查是不是有空连接,也是需要论询的,呵呵,所以
存在状态也是合理的,
 
to melice:虽然一个线程最多可以等候64个连接,但ServerSocket的线程只等候一个连接。
to 王寒松:服务器可能不会马上知道某个客户机已经断开,但不需要太长时间肯定能够收
到。换句话说:轮询过程是系统完成成,用户干预纯属多余。
btw:我真的这么话多吗?

最近一个多星期我都在review我项目中的WinSock方面的代码。所以对本贴有些兴趣。过一
两天我会拿出我的测试结果来。我以一个简单的Chat服务器和客户端为模型,看看每一种
IO模式到底最多能够承载多少连接。
 
>>轮询过程是系统完成成,用户干预纯属多余
TCP好象不干这个哦,即使你设置了哪个标志,最短时间也是2个小时,没有任何使用价值!
 
后退
顶部