SIO_KEEPALIVE_VALS 用户异常掉线检测

本文介绍了三种用户掉线检测方案:SO_KEEPALIVE、SIO_KEEPALIVE_VALS及Heart-Beat线程。讨论了各方案的实现方式、优缺点,并提供DELPHI心跳检测示例。

       用户异常掉线检测
                                 David.Zhu  2005/6/1
   目前主要有三种方法来实现用户掉线检测:SO_KEEPALIVE ,SIO_KEEPALIVE_VALS 和Heart-Beat线程。
下面我就上面的三种方法来做一下介绍。
(1)SO_KEEPALIVE 机制
        这是socket库提供的功能,设置接口是setsockopt API:
   BOOL  bSet=TRUE;
   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就会在一定的时间(比如你设置的是3秒钟)内发送你设置的次数的心跳(比如说2次),并且此信息不会影响你自己定义的协议。

  在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;
      //设置3秒钟时间间隔

  inKeepAlive.keepalivetime:=3000;

      //设置每3秒中发送1次的心跳
      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;

如果加入以上的代码以后,系统会每3秒中加入一次的心跳。并且如果客户端断线以后(网线断),函数GetQueuedCompletionStatus会返回FALSE。

if (GetQueuedCompletionStatus(CompletionPort, BytesTransferred,DWORD(PerHandleData), POverlapped(PerIoData), INFINITE) = False) then
        begin
           //在这里处理客户端断线信息。

   continue;
        end;

以上就是我使用心跳的方法,此方法我已经在我的网络游戏中使用。情况稳定!

<think> 我们正在分析一段Python代码,它使用了`server.ioctl`方法,并传递了两个参数:`qp.socket.SIO_KEEPALIVE_VALS`和一个元组`(1, 60 * 1000, 30 * 1000)`。 根据用户提供的引用,我们可以知道: 1. `WSAIoctl`函数(在Windows中)用于设置套接字选项,特别是TCP心跳参数(引用[1])。 2. 心跳参数使用一个结构体`tcp_keepalive`,包含三个成员:`onoff`(是否开启)、`keepalivetime`(首次探测前的空闲时间)和`keepaliveinterval`(探测间隔时间)(引用[1])。 3. 常量`SIO_KEEPALIVE_VALS`的定义方式(引用[2]):它是通过按位或组合`IOC_IN`、`IOC_VENDOR`和`4`得到的。 4. 在Windows中,心跳探测次数固定为10次,不可修改(引用[3])。 代码中使用的常量`qp.socket.SIO_KEEPALIVE_VALS`应该就是对应Windows中定义的`SIO_KEEPALIVE_VALS`。 代码的第二个参数是一个元组,包含三个值: - 第一个值:1 -> 对应结构体`tcp_keepalive`的`onoff`,表示开启心跳。 - 第二个值:60 * 1000 = 60000毫秒(即60秒)-> 对应`keepalivetime`,表示连接空闲60秒后开始发送心跳包。 - 第三个值:30 * 1000 = 30000毫秒(即30秒)-> 对应`keepaliveinterval`,表示每次心跳探测的间隔时间为30秒。 因此,这行代码的作用是:在服务器套接字上启用TCP心跳机制,设置空闲60秒后开始发送心跳包,之后每隔30秒发送一次。如果连续10次(Windows固定)没有收到响应,则断开连接。 总结:这段代码用于设置TCP连接的保活(keepalive)参数,以防止由于网络不稳定或对方异常断开导致连接长时间无效占用资源。 注意:根据引用[3],在Windows系统中,心跳探测次数固定为10次,因此这里没有设置次数的参数。而在Linux系统中,我们可以通过修改`/proc/sys/net/ipv4/tcp_keepalive_probes`来改变探测次数。 相关问题: 1. 在非Windows系统(如Linux)中如何设置TCP心跳参数? 2. 除了心跳机制,还有哪些方法可以检测TCP连接的有效性? 3. 心跳机制在实际网络编程中的应用场景有哪些? </think> ### 代码含义与用途解析 您提供的代码 `server.ioctl(qp.socket.SIO_KEEPALIVE_VALS, (1, 60 * 1000, 30 * 1000))` 用于在Socket网络编程中设置TCP连接的心跳保活机制,具体功能如下: --- #### 1. **核心功能** - **启用TCP心跳机制**: - 第一个参数 `qp.socket.SIO_KEEPALIVE_VALS` 是Windows系统的专用常量,表示设置TCP心跳参数[^2]。 - 第二个参数元组 `(1, 60 * 1000, 30 * 1000)` 对应TCP心跳配置: - `1`:启用心跳(`onoff=1`) - `60 * 1000`:首次探测等待时间(**60秒**) - `30 * 1000`:后续探测间隔时间(**30秒**) #### 2. **参数含义** ```python ( onoff, keepalivetime, keepaliveinterval ) ``` - **`onoff=1`**: 启用TCP心跳机制(设为0则禁用)[^1]。 - **`keepalivetime=60,000ms`**: 连接**空闲60秒后**发送第一个心跳探测包。 - **`keepaliveinterval=30,000ms`**: 若未收到响应,**每30秒**重发一个探测包[^1]。 #### 3. **底层原理** - 对应Windows的`tcp_keepalive`结构体: ```c struct tcp_keepalive { u_long onoff; // 开关(1启用) u_long keepalivetime; // 首次探测时间(ms) u_long keepaliveinterval; // 探测间隔(ms) }; ``` - 探测失败后,Windows会**固定重试10次**(不可修改),最终断开连接[^3]。 #### 4. **实际用途** - **检测失效连接**: 当客户端异常断网(如崩溃、断电)时,通过心跳包快速发现失效连接。 - **释放资源**: 避免服务器长期维持"僵尸连接",节省Socket资源。 - **网络稳定性**: 在NAT环境下保持连接活性,防止路由器超时重置。 --- ### 与其他函数的区别 | 函数 | 适用场景 | 特点 | |-------------|---------------------------|------------------------------| | `ioctlsocket` | 基础IO控制(如阻塞模式) | 通用但不支持高级TCP参数[^1] | | `setsockopt` | 标准Socket选项(如超时) | 跨平台但无心跳精细控制[^1] | | **`WSAIoctl`** | **Windows高级选项** | **唯一支持TCP心跳参数**[^1] | > ⚠️ 注意:Linux中需通过`setsockopt`设置`SO_KEEPALIVE`,并用`/proc/sys/`调整参数[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值