网站报价收费单,店铺推广策略,浙江省城乡与住房建设部网站,做坑人网站二维码由于用QTcpSocket写网络通讯程序#xff0c;当正常服务端或者客户端断开的时候#xff0c;我们监测信号即可#xff1a;Signals#xff1a;stateChanged(QAbstractSocket::SocketState)。#xff08;手动关闭网络连接#xff0c;也会检测到断开#xff09; 但是当若是有…由于用QTcpSocket写网络通讯程序当正常服务端或者客户端断开的时候我们监测信号即可SignalsstateChanged(QAbstractSocket::SocketState)。手动关闭网络连接也会检测到断开 但是当若是有一端无故突然被拔掉网线这个信号就检测不到TcpSocket已经断开了而且她仍然是连接状态。 那么我们这个时候就需要考虑到心跳信号了。 在Qt中已经提供了QAbstractSocket::KeepAliveOption clientSocket-setSocketOption(QAbstractSocket::KeepAliveOption, 1); 然后去win7系统注册表中更改 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] “KeepAliveTime”1000 ms32dword“KeepAliveInterval”1000ms32dword 重启机器。 测试一下拔掉网线后是否激活了disconnected信号。我感觉还是花了5s左右才会检测到网线断了。 所以根本方法还是得用心跳机制。 如下内容总结了3种检测掉线的机制。 转载http://www.cnblogs.com/BeginGame/archive/2011/09/24/2189750.html 用户异常掉线检测 David.Zhu 2005/6/1 目前主要有三种方法来实现用户掉线检测SO_KEEPALIVE ,SIO_KEEPALIVE_VALS 和Heart-Beat线程。 下面我就上面的三种方法来做一下介绍。 (1)SO_KEEPALIVE 机制 这是socket库提供的功能设置接口是setsockopt API BOOL bSetTRUE; setsockopt(hSocket,SOL_SOCKET,SO_KEEPALIVE,(const char*)bSet,sizeof(BOOL)); 根据MSDN的文档如果为socket设置了KEEPALIVE选项TCP/IP栈在检测到对方掉线后 任何在该socket上进行的调用(发送/接受调用)就会立刻返回错误号是WSAENETRESET 同时此后的任何在该socket句柄的调用会立刻失败并返回WSAENOTCONN错误。 该机制的缺点也很明显 默认设置是空闲2小时才发送一个“保持存活探测分节”不能保证实时检测 当然也可以修改时间间隔参数但是会影响到所有打开此选项的套接口 关联了完成端口的socket可能会忽略掉该套接字选项。 (2)SIO_KEEPALIVE_VALS 机制 这是从彭博兄那里学到一个机制拉设置接口是WSAIoctl API: DWORD dwError 0L ; tcp_keepalive sKA_Settings {0}, sReturned {0} ; sKA_Settings.onoff 1 ; sKA_Settings.keepalivetime 5500 ; // Keep Alive in 5.5 sec. sKA_Settings.keepaliveinterval 3000 ; // Resend if No-Reply if (WSAIoctl(skNewConnection, SIO_KEEPALIVE_VALS, sKA_Settings, sizeof(sKA_Settings), sReturned, sizeof(sReturned), dwBytes, NULL, NULL) ! 0) { dwError WSAGetLastError() ; } 实现时需要添加tcp_keepalive and SIO_KEEPALIVE_VALS的定义文件MSTCPiP.h 该选项不同于SO_KEEPALIVE 机制的就是它是针对单个连接的对系统其他的套接 口并不影响。 针对完成端口的socket,设置了SIO_KEEPALIVE_VALS后激活包由TCP STACK来负责。 当网络连接断开后TCP STACK并不主动告诉上层的应用程序但是当下一次RECV或者SEND操作 进行后马上就会返回错误告诉上层这个连接已经断开了.如果检测到断开的时候在这个连接 上有正在PENDING的IO操作则马上会失败返回. 该机制的缺点 不通用啦。MS的API只能用于Windows拉。不过呵呵用彭博兄的评论就是 优雅一些^_^. (3)Heart-Beat线程 没说的。自己写一个后台线程实现Heart-Beat包客户端受到该包后立刻返回相应的反馈 包。 该方法的好处是通用但缺点就是会改变现有的通讯协议 有开发网络应用经历的人都知道网络中的接收和发送数据都是使用WINDOWS中的SOCKET进行实现。但是如果此套接字已经断开那发送数据和接收数据的时候就一定会有问题。可是如何判断这个套接字是否还可以使用呢 有人一定想到使用Send函数中的返回结果来进行判断。如果返回的长度和自己发送出去的长度一致那就说明这个套接字是可用的否则此套接字一定出现了问题。但是我们并不是无时无刻的发送数据呀。如何解决呢 其实TCP中已经为我们实现了一个叫做心跳的机制。如果你设置了心跳那TCP就会在一定的时间比如你设置的是秒钟内发送你设置的次数的心跳比如说次并且此信息不会影响你自己定义的协议。 在VC中实现心跳的例子很多可是在DLEPHI中一直没有相应的代码。下面我是我使用DELPHI编写的关于心跳的代码以IOCP为例希望对大家有帮助。 定义心跳常量 const IOC_IN $80000000; IOC_VENDOR $18000000; IOC_out $40000000; SIO_KEEPALIVE_VALS IOC_IN or IOC_VENDOR or 4; var inKeepAlive,OutKeepAlive:TTCP_KEEPALIVE; 实现代码是在Acceptsc: WSAAccept(Listensc, nil, nil, nil, 0);代码的后面加入 opt:1; if setsockopt(Acceptsc,SOL_SOCKET,SO_KEEPALIVE,opt,sizeof(opt))SOCKET_ERROR then begin closesocket(Acceptsc); end; inKeepAlive.onoff:1; //设置秒钟时间间隔 inKeepAlive.keepalivetime:3000; //设置每秒中发送次的心跳 inKeepAlive.keepaliveinterval:1; insize:sizeof(TTCP_KEEPALIVE); outsize:sizeof(TTCP_KEEPALIVE); if WSAIoctl(Accept,SIO_KEEPALIVE_VALS,inKeepAlive,insize,outKeepAlive,outsize,outByte,nil,nil)SOCKET_ERROR then begin closesocket(Acceptsc); end; 如果加入以上的代码以后系统会每秒中加入一次的心跳。并且如果客户端断线以后网线断函数GetQueuedCompletionStatus会返回FALSE。 if (GetQueuedCompletionStatus(CompletionPort, BytesTransferred,DWORD(PerHandleData), POverlapped(PerIoData), INFINITE) False) then begin //在这里处理客户端断线信息。 continue; end; 以上就是我使用心跳的方法此方法我已经在我的网络游戏中使用。情况稳定 转自http://www.lofter.com/tag/qtcpsocket转载于:https://www.cnblogs.com/liushui-sky/p/6497158.html