delphi idtcpclient和idtcpserver的心跳包

delphi idtcpclient和idtcpserver的心跳包


最近有个项目需要用到socket通信,对于socket的网络异常处理(程序异常退出或者网络掉了)及重连纠结了好久,网上虽然有很多资料,但是都是从一个地方转过来的,不够详细,查了很久的资料才弄出来的,原来的出处给忘了。

环境:delphi7+indy控件(dephi7自带)     工作需要才用delphi7,建议使用delphi2007及以上版本,delphi2007里面带的indy控件版本是10.0,修复了很多以前的bug

使用心跳包的理由:(ps:以下理由是抄的,感觉意思和我当初的初衷是一样的)
有开发网络应用经历的人都知道,网络中的接收和发送数据都是使用WINDOWS中的SOCKET进行实现。但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题。可是如何判断这个套接字是否还可以使用呢?
  有人一定想到使用Send函数中的返回结果来进行判断。如果返回的长度和自己发送出去的长度一致,那就说明这个套接字是可用的,否则此套接字一定出现了问题。但是我们并不是无时无刻的发送数据呀。如何解决呢?
  其实TCP中已经为我们实现了一个叫做心跳的机制。如果你设置了心跳,那TCP就会在一定的时间(比如你设置的是3秒钟)内发送你设置的次数的心跳(比如说2次),并且此信息不会影响你自己定义的协议。
 
原理网上都有,就是使用setsockopt函数和WSAIoctl函数,网上光介绍了怎么使用心跳机制,没有说处理办法。设置好心跳后,TCP就会在一定的时间(比如你设置的是3秒钟)内发送你设置的次数的心跳(比如说2次),如果网络异常(程序异常退出或者网络掉了),心跳就会抛出一个错误异常,我们只要知道在哪儿捕获异常,就能知道网络情况以及何时进行重连了。
 
服务端的心跳处理(idtcpserver)
  //定义心跳常量
Const
  IOC_IN = $80000000;
  IOC_VENDOR = $18000000;
  IOC_out = $40000000;
  SIO_KEEPALIVE_VALS = IOC_IN or IOC_VENDOR or 4;
  DATA_BUFSIZE = 8192;
 
//定义 KeepAlive 数据结构
Type
  TTCP_KEEPALIVE = packed record
    onoff: integer;
    keepalivetime: integer;
    keepaliveinterval: integer;
  end;
在idtcpserver的OnConnect事件里面加入以下代码:
var
  opt:Integer;
  klive, outKlive: TTCP_KEEPALIVE;
begin
  opt := 1;
    if setsockopt(AThread.Connection.Socket.Binding.Handle,SOL_SOCKET, SO_KEEPALIVE, @opt, SizeOf(opt)) <> 0 then
    begin
      Showmessage('setsockopt KeepAlive Error!');
    end;
    klive.onoff := 1;
    klive.keepalivetime := 3000;
    klive.keepaliveinterval := 1;
    if WSAIoctl(AThread.Connection.Socket.Binding.Handle, SIO_KEEPALIVE_VALS, @klive,
             SizeOf(TTCP_KEEPALIVE), @outKlive,
             SizeOf(TTCP_KEEPALIVE), @opt,0,nil) = SOCKET_ERROR then
    begin
      Showmessage('WSAIoctl KeepAlive Error!');
    end
end
在idtcpserver的OnException事件里面就能捕获到这个异常,并进行异常处理了
procedure Tfrmmain.IdTCPServer1Exception(AThread: TIdPeerThread;
  AException: Exception);
begin
  suiMemo1.Lines.Add('客户端'+inttostr(athread.handle)+'异常断开');
  if AThread.Connection.Connected then AThread.Connection.Disconnect;
end;
 
 
客户端的心跳处理(idtcpclient)
procedure Tfrmmain.IdTCPClient1Connected(Sender: TObject);
var
    opt:Integer;
  klive, outKlive: TTCP_KEEPALIVE;
begin
    opt := 1;
    if setsockopt(IdTCPClient1.Socket.Binding.Handle,SOL_SOCKET, SO_KEEPALIVE, @opt, SizeOf(opt)) <> 0 then
    begin
      Showmessage('setsockopt KeepAlive Error!');
    end;
    klive.onoff := 1;
    klive.keepalivetime := 3000;
    klive.keepaliveinterval := 1;
    if WSAIoctl(IdTCPClient1.Socket.Binding.Handle, SIO_KEEPALIVE_VALS, @klive,
             SizeOf(TTCP_KEEPALIVE), @outKlive,
             SizeOf(TTCP_KEEPALIVE), @opt,0,nil) = SOCKET_ERROR then
    begin
      Showmessage('WSAIoctl KeepAlive Error!');
    end;
end;
 
客户端的异常捕捉,我是放在客户端读取服务端发送过来数据的线程里面
procedure TReadThread.Execute;
var
  TestBuffer:TSendDataNet;
begin
  { Place thread code here }
  frmmain.log('Client Begin reading...');
  while permit do
  begin
    try
      frmmain.IdTCPClient1.ReadBuffer(TestBuffer,SizeOf(TestBuffer));
      sleep(100);
    except
      on e:Exception do
      begin
        permit:=False;
        if frmmain.IdTCPClient1.Connected then frmmain.IdTCPClient1.Disconnect;
        frmmain.RzStatusPane1.Caption:='断开;
        frmmain.LinkTimer.Enabled:=True;//这儿启动定时器重连服务端
      end;
    end;
  end;
  ThreadDestroy;
end;

转载于:https://www.cnblogs.com/moonwind/p/4434608.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值