开发环境:Delphi7
测试环境:WinXP,Win7 32bit,Win7 64bit
使用TClientSocket和TServerSocket实现TCP长连接通讯,经常因为断电断网等原因导致出现一些死连接。
解决方法是客户端和服务端都定时发送心跳包。
具体实现如下:
TClientSocket和TServerSocket均使用非阻塞模式
1、定义心跳常量和KeepAlive 数据结构
//定义心跳常量
Const
IOC_IN = $;
IOC_VENDOR = $;
IOC_out = $;
SIO_KEEPALIVE_VALS = IOC_IN or IOC_VENDOR or ;
DATA_BUFSIZE = ; //定义 KeepAlive 数据结构
Type
TTCP_KEEPALIVE = packed record
onoff: integer;
keepalivetime: integer;
keepaliveinterval: integer;
end;
2、引用WinSock,WinSock2
3、写一个方法来使用setsockopt,WSAIoctl设置心跳包参数
procedure TForm1.setKeepAlive(Socket: TCustomWinSocket);
var
opt:Integer;
klive, outKlive: TTCP_KEEPALIVE;
i,j:integer;
OptVal: DWORD;
begin
opt := ;
//需引用WinSock.pas
if setsockopt(Socket.SocketHandle,SOL_SOCKET, SO_KEEPALIVE, PAnsiChar(@opt), SizeOf(opt)) = SOCKET_ERROR then
begin
showInfo(Format('WinSock Error %d', [WSAGetLastError()]));
end;
klive.onoff := ;
klive.keepalivetime := ;
klive.keepaliveinterval := ;
//需引用WinSock2.pas
if WSAIoctl(Socket.SocketHandle, SIO_KEEPALIVE_VALS, PAnsiChar(@klive),
SizeOf(TTCP_KEEPALIVE), PAnsiChar(@outKlive),
SizeOf(TTCP_KEEPALIVE), @opt,,nil) = SOCKET_ERROR then
begin
showInfo(Format('WinSock Error %d', [WSAGetLastError()]));
end; end;
4、在TClientSocket和TServerSocket的连接事件中调用设置心跳
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
showInfo('ServerSocket1ClientConnect-' + Socket.RemoteAddress + ':' + IntToStr(Socket.RemotePort));
setKeepAlive(Socket); //设置socket心跳,以便清除死链接
end;
经测试,采用以上方法,可以检测到把网线断网情况
测试效果图: