• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

delphiidtcpclient和idtcpserver的心跳包

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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;


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
图像几何变换之平移(Matlab)发布时间:2022-07-18
下一篇:
matlab 图像平移操作发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap