文章目录

  • 判断socket连接断开的方法
    • 法一:判断recv()返回值
      • 但是参考这篇文章的代码,程序居然被阻塞了,不知道怎么回事
    • 法二:创建tcp_info结构体,判断info.tcpi_state是否为TCP_ESTABLISHED(注意:需包含tcp.h)
    • 法三:用select函数的方法(没太看懂)
    • 法四:用keepalive属性
      • 说明
      • 有关SO_KEEPALIVE的三个参数详细解释如下
  • 法五:自己实现心跳检测

判断socket连接断开的方法

法一:判断recv()返回值

当recv()返回值小于等于0时,socket连接断开。但是还需要判断 errno是否等于 EINTR,如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的,不应close掉socket连接。

但是参考这篇文章的代码,程序居然被阻塞了,不知道怎么回事

参考文章:如何在C语言中判断socket是否已经断开

#include <errno.h> bool IsSocketClosed(int clientSocket)
{ char buff[32]; int recvBytes = recv(clientSocket, buff, sizeof(buff), MSG_PEEK); int sockErr = errno; //cout << "In close function, recv " << recvBytes << " bytes, err " << sockErr << endl; if( recvBytes > 0) //Get data return false; if( (recvBytes == -1) && (sockErr == EWOULDBLOCK) ) //No receive data return false; return true;
}

法二:创建tcp_info结构体,判断info.tcpi_state是否为TCP_ESTABLISHED(注意:需包含tcp.h)

  struct tcp_info info; int len=sizeof(info); getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len); if((info.tcpi_state==TCP_ESTABLISHED))  //则说明未断开  else 断开

法三:用select函数的方法(没太看懂)

若使用了select等系统函数,若远端断开,则select返回1,recv返回0则断开。其他注意事项同法一。

法四:用keepalive属性

int keepAlive = 1; // 开启keepalive属性
int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测
int keepInterval = 5; // 探测时发包的时间间隔为5 秒
int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void )&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void
)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

设置后,若断开,则在使用该socket读写时立即失败,并返回ETIMEDOUT错误

说明

socket心跳机制so_keepalive的三个参数详解

SO_KEEPALIVE 保持连接检测对方主机是否崩溃,避免(服务器)永远阻塞于TCP连接的输入。

设置该选项后,如果2小时内在此套接口的任一方向都没有数据交换,TCP就自动给对方 发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况:

1、对方接收一切正常:以期望的ACK响应,2小时后,TCP将发出另一个探测分节。

2、对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口本身则被关闭。

3、对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到一个响应。在发出第一个探测分节11分钟15秒后若仍无响应就放弃。套接口的待处理错误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。

有关SO_KEEPALIVE的三个参数详细解释如下

(16)tcp_keepalive_intvl,保活探测消息的发送频率。默认值为75s。

发送频率tcp_keepalive_intvl乘以发送次数tcp_keepalive_probes,就得到了从开始探测直到放弃探测确定连接断开的时间,大约为11min。

(17)tcp_keepalive_probes,TCP发送保活探测消息以确定连接是否已断开的次数。默认值为9(次)。

注意:只有设置了SO_KEEPALIVE套接口选项后才会发送保活探测消息。

(18)tcp_keepalive_time,在TCP保活打开的情况下,最后一次数据交换到TCP发送第一个保活探测消息的时间,即允许的持续空闲时间。默认值为7200s(2h)。

法五:自己实现心跳检测

自己实现一个心跳检测,一定时间内未收到自定义的心跳包则标记为已断开。

TCP中已有SO_KEEPALIVE选项,为什么还要在应用层加入心跳包机制?
首先,我想说的是,SO_Keeplive是实现在服务器侧,客户端被动响应,缺省超时时间为120分钟,这是RFC协议标准规范。

SO_Keeplive是实现在TCP协议栈(四层),应用层的心跳实现在第七层,本质没有任何区别,但应用层需要自己来定义心跳包格式。

之所以实现在服务器侧,是因为与客户端相比,服务器侧的寿命更长,因为服务器侧需要不间断地提供服务,而客户端可能由于用户下班而合上电脑(TCP没有来得及发送FIN关闭连接),这样的话,服务器侧就会有很多不可用的TCP连接(established),这样的连接依然会占用服务器内存资源,于是就设计这个keepalive 来检测客户端是否可用,如果几次重传keepalive ,客户端没有相应,删除连接,释放资源。

需要指出的是,超时时间是指TCP连接没有任何数据、控制字传输的时间,如果有任何数据传输,会刷新定时器,重新走表。

TCP心跳是一个备受争议的实现,只是一个option,不是强制标准。

之所以应用层需要独立实现自己的心跳,是因为超时时间较长,无法给应用层提供快速的反馈。

所以类似BGP协议就独立实现了自己的keepalive,最小可以设置一秒钟,三次没有应答即可以Reset连接,最快三秒可以检测到失效。

而三秒依然太慢,可以用另外一个协议BFD来提供更快发现链路失效,最快可以配置成10ms
,三次超时(30ms)就可以完成失效检测。

区别
tcp keepalive检查连接是否存活。
应用keppalive检测应用是否正常可响应。

举个例子。服务端死锁,无法处理任何业务请求。但是操作系统仍然可以响应网络层keepalive包。

参考文章:判断socket连接断开的方法

linux C语言 socket如何判断socket_fd对应的socket是否断开?(是否连通、是否正常连接)recv()、tcp_info TCP_ESTABLISHED、keepalive相关推荐

  1. linux C语言 socket编程教程(附两个例子)(socket教程)

    文章目录 1.网络中进程之间如何通信? 2.什么是Socket? 3.socket的基本操作 3.1.socket()函数 3.2.bind()函数 网络字节序与主机字节序 3.3.listen(). ...

  2. linux C语言access()函数(检查用户对文件的权限)(判断文件是否存在)

    文章目录 man 2 access 20220601 不知道上面所说的pathname的符号链接取消引用是什么意思 man 2 access ACCESS(2) Linux Programmer's ...

  3. linux c 判断文件是否存在,C语言中如何判断文件是否存在

    C语言中如何判断文件是否存在 方法一:access函数判断文件夹或者文件是否存在 函数原型: int access(const char *filename, int mode); 所属头文件:io. ...

  4. [linux][c语言]用socket实现简单的服务器客户端交互

    Socket解释: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket的英文原义是"孔"或"插座".作为B ...

  5. linux C语言多线程库pthread中条件变量的正确用法逐步详解

    linux C语言多线程库pthread中条件变量的正确用法: 了解pthread常用多线程API和pthread互斥锁,但是对条件变量完全不知道或者不完全了解的人群. 关于条件变量的典型应用,可以参 ...

  6. linux c语言编程(转)

    linux操作系统下 c语言编程入门 整理编写:007xiong 原文:Hoyt等 (一)目录介绍 1)Linux程序设计入门--基础知识 2)Linux程序设计入门--进程介绍 3)Linux程序设 ...

  7. linux c语言 select函数用法

    原文地址:点击打开链接 linux c语言 select函数用法 Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如 co ...

  8. 《全面掌握Linux C语言嵌入式系统移植教程》学习笔记(Liunx速查简明)

    全面掌握Linux C语言嵌入式系统移植教程学习笔记(Liunx速查简明) 笔记前言: P3: shell命令简明 P4: vi /vim编辑器入门 P5:vi /vim编辑器扩展 P8: gcc编译 ...

  9. 嵌入式linux寄存器位运算,嵌入式linux C语言(一)――位运算的使用

    嵌入式linux C语言(一)――位运算的使用 ARM是内存与IO统一编址,SoC中有很多控制寄存器,通过对这些寄存器进行位运算对这些控制寄存器进行设置,进而控制外设功能.在修改寄存器某些位的过程中不 ...

最新文章

  1. OpenCV(二十)模板匹配
  2. 日本依靠储能系统解决光伏消纳问题
  3. 51Node 01组成的N的倍数
  4. 线程其实就是一个个指令组成的,当这个线程内的指令全部执行完了,那么这个线程也就执行结束了
  5. 云原生/低代码/数据科学/计算等方向内容整理志愿者招募了!
  6. IOS – OPenGL ES 调节图像饱和度 GPUImageSaturationFilter
  7. 需求分析文档模板_我们应该如何进行需求管理「下篇」?
  8. 实现简单的Console
  9. MATLAB 图像处理之图片区域显示
  10. 朗格Lange 1古董车展特别版表落谁家?法拉利 335 Sport非常合衬
  11. flutter2.x报错解决type (RouteSettings) => Route<dynamic> is not a subtype of type (RouteSettings) => Rou
  12. 路飞学城python开发ftp_路飞学城-Python开发集训-第1章
  13. djay Pro 2 Mac(DJ混音软件) v2.0.11激活版
  14. 星鲨StarSharks游戏打金攻略和收益详解
  15. Equalize Them All(思维)
  16. 用kNN算法诊断乳腺癌--基于R语言
  17. APP测试与WEB测试的区别
  18. 游戏设计艺术 第2版 第30章 读书笔记
  19. 10条必知的网页导航菜单设计原则
  20. Cuda CuDnn Pytorch 安装 print(torch.cuda.is_available())输出报错。NVDIA 940MX

热门文章

  1. 10套华丽的 Windows 8 Metro 风格图标【2000+免费图标】
  2. linux挂载新硬盘,开机自动挂载
  3. JQuery学习系列(九)AJAX
  4. SAP HANA 三大特点
  5. 【重复制造精讲】REM Pull List 拉料单(续)
  6. 【实用】SAP修改记录表开发
  7. WebService入门详解
  8. SAP--DEBUG--外部断点的设置
  9. SAP CRM几个常用的使用技巧
  10. 中国34城最全剖析:深圳、天津的短板与不足,何时才能补?