如何判断SOCKET已经断开
来源:互联网 发布:mysql怎么取消主键 编辑:程序博客网 时间:2024/04/30 02:42
http://biancheng.dnbcw.info/linux/366100.html
最近在做一个服务器端程序,C/S结构。功能方面比较简单就是client端与server端建立连接,然后发送消息给server。我在server端会使用专门的线程处理一条socket连接。这就涉及到一个问题,如果socket连接断开(异常,正常)后,我如何才能感知到?server端这边是绝对被动的,sever端不能主动断开连接。也没有连接链路维持包之类的。client端发送数据的时间也是不定的。在socket连接断开后, server要能够感知到并释放资源。
这个问题在思考测试,询问同事之后,找到了一个方法,可以做到这一点。
当使用 select()函数测试一个socket是否可读时,如果select()函数返回值为1,且使用recv()函数读取的数据长度为0 时,就说明该socket已经断开。
为了更好的判定socket是否断开,我判断当recv()返回值小于等于0时,socket连接断开。但是还需要判断 errno是否等于 EINTR 。如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的,不应close掉socket连接。
PS:对于堵塞socket的recv函数会在以下三种情况下返回:
(1)recv到数据时,会返回。
(2)在整个程序接收到信号时,返回-1。errno = EINTR。//在程序的起始阶段,屏蔽掉信号的除外。部分信号还是屏蔽不掉的。
(3)socket出现问题时,返回-1.具体错误码看 man recv()
(4)一定要看 man 说明,很详细,很有帮助。
这种方法经过长时间测试后,是有效的。所以写出来让大家参考一下,请大家发表意见。
我的方法不一样,我用getsockopt来判断,还是蛮准确的
tcp_info和TCP_ESTABLISHED在linux/tcp.h
包含
目前主要有三种方法来实现用户掉线检测: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:
实现时需要添加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包,客户端受到该包后,立刻返回相应的反馈 包。
该方法的好处是通用,但缺点就是会改变现有的通讯协议!
最近在做一个服务器端程序,C/S结构。功能方面比较简单就是client端与server端建立连接,然后发送消息给server。我在server端会使用专门的线程处理一条socket连接。这就涉及到一个问题,如果socket连接断开(异常,正常)后,我如何才能感知到?server端这边是绝对被动的,sever端不能主动断开连接。也没有连接链路维持包之类的。client端发送数据的时间也是不定的。在socket连接断开后, server要能够感知到并释放资源。
这个问题在思考测试,询问同事之后,找到了一个方法,可以做到这一点。
当使用 select()函数测试一个socket是否可读时,如果select()函数返回值为1,且使用recv()函数读取的数据长度为0 时,就说明该socket已经断开。
为了更好的判定socket是否断开,我判断当recv()返回值小于等于0时,socket连接断开。但是还需要判断 errno是否等于 EINTR 。如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的,不应close掉socket连接。
PS:对于堵塞socket的recv函数会在以下三种情况下返回:
(1)recv到数据时,会返回。
(2)在整个程序接收到信号时,返回-1。errno = EINTR。//在程序的起始阶段,屏蔽掉信号的除外。部分信号还是屏蔽不掉的。
(3)socket出现问题时,返回-1.具体错误码看 man recv()
(4)一定要看 man 说明,很详细,很有帮助。
这种方法经过长时间测试后,是有效的。所以写出来让大家参考一下,请大家发表意见。
我的方法不一样,我用getsockopt来判断,还是蛮准确的
点击(此处)折叠或打开
- int SocketConnected(int sock)
- {
- if (sock <= 0)
- return 0;
- struct tcp_info info;
- int len = sizeof(info);
- getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *) & len);
- if ((info.tcpi_state == TCP_ESTABLISHED)) {
- //myprintf("socket connected\n");
- return 1;
- } else {
- //myprintf("socket disconnected\n");
- return 0;
- }
- }
包含
点击(此处)折叠或打开
- #include <linux/types.h>
- #include <asm/byteorder.h>
- #include <linux/config.h>
- #include <linux/skbuff.h>
- #include <linux/ip.h>
- #include <net/sock.h>
- http: //www.cse.scu.edu/~dclark/am_256_graph_theory/linux_2_6_stack/globals.html#index_t
- int SocketConnected(int sock)
- {
- if (sock <= 0)
- return 0;
- struct tcp_info info;
- int len = sizeof(info);
- getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *) & len);
- if ((info.tcpi_state == TCP_ESTABLISHED)) {
- //myprintf("socket connected\n");
- return 1;
- } else {
- //myprintf("socket disconnected\n");
- return 0;
- }
- }
下面我就上面的三种方法来做一下介绍。
(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() ;
- }
该选项不同于SO_KEEPALIVE 机制的就是它是针对单个连接的,对系统其他的套接
口并不影响。
针对完成端口的socket,设置了SIO_KEEPALIVE_VALS后,激活包由TCP STACK来负责。
当网络连接断开后,TCP STACK并不主动告诉上层的应用程序,但是当下一次RECV或者SEND操作
进行后,马上就会返回错误告诉上层这个连接已经断开了.如果检测到断开的时候,在这个连接
上有正在PENDING的IO操作,则马上会失败返回.
该机制的缺点:
不通用啦。MS的API只能用于Windows拉。不过,优雅一些^_^.
(3)Heart-Beat线程
没说的。自己写一个后台线程,实现Heart-Beat包,客户端受到该包后,立刻返回相应的反馈 包。
该方法的好处是通用,但缺点就是会改变现有的通讯协议!
点击(此处)折叠或打开
- /* Net check Make sure you have not used OUT OF BAND DATA AND YOU CAN use OOB */
- int netcheck(int fd)
- {
- int buf_size = 1024;
- char buf[buf_size];
- //clear OOB DATA
- recv(fd, buf, buf_size);
- if (send(fd, (void *)"\0", 1, MSG_OOB) < 0) {
- fprintf(stderr, "Connection[%d] send OOB failed, %s", fd, strerror(errno));
- return -1;
- }
- return 0;
- }
- //复制代码
- /* Setting SO_TCP KEEPALIVE */
- //int keep_alive = 1;//设定KeepAlive
- //int keep_idle = 1;//开始首次KeepAlive探测前的TCP空闭时间
- //int keep_interval = 1;//两次KeepAlive探测间的时间间隔
- //int keep_count = 3;//判定断开前的KeepAlive探测次数
- void set_keepalive(int fd, int keep_alive, int keep_idle, int keep_interval, int keep_count)
- {
- int opt = 1;
- if (keep_alive) {
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keep_alive, sizeof(keep_alive)) == -1) {
- fprintf(stderr, "setsockopt SOL_SOCKET::SO_KEEPALIVE failed, %s\n", strerror(errno));
- }
- if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void *)&keep_idle, sizeof(keep_idle)) == -1) {
- fprintf(stderr, "setsockopt SOL_TCP::TCP_KEEPIDLE failed, %s\n", strerror(errno));
- }
- if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keep_interval, sizeof(keep_interval)) == -1) {
- fprintf(stderr, "setsockopt SOL_tcp::TCP_KEEPINTVL failed, %s\n", strerror(errno));
- }
- if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void *)&keep_count, sizeof(keep_count)) == -1) {
- fprintf(stderr, "setsockopt SOL_TCP::TCP_KEEPCNT failed, %s\n", strerror(errno));
- }
- }
- }
0
上一篇:accept() returns the same socket descriptor
下一篇:(OK) C/S—心跳检测—heartbeat
相关热门文章
- test123
- 编写安全代码——小心有符号数...
- 使用openssl api进行加密解密...
- 一段自己打印自己的c程序...
- sql relay的c++接口
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- 如何判断socket已经断开
- 如何判断socket已经断开
- 如何判断SOCKET已经断开
- 如何判断socket已经断开
- 如何判断socket已经断开
- Java如何判断socket是否已经断开
- 如何判断一个SOCKET连接是否已经断开
- 如何判断一个SOCKET连接是否已经断开
- 【VS开发】如何判断客户端SOCKET已经断开连接?
- 如何判断一个SOCKET连接是否已经断开
- java 怎么判断socket已经断开
- C 判断socket 是否已经断开
- 如何判断socket客户端断开
- 如何判断Socket是否断开
- 如何判断Socket是否断开
- 如何判断一个tcp连接已经断开
- 如何判断socket是否已经断开和防止外部攻击,只连接不传输数据
- Javaclient端怎么判断server端socket是否已经断开
- 阶乘之和
- Linux—Network—Socket—Programming—heartbeat—源代码
- C/S—心跳检测—heartbeat
- 分析Servlet、Filter、Interception和Listener
- accept() returns the same socket descriptor
- 如何判断SOCKET已经断开
- 使用java 和freemarker实现多级菜单(分类)
- Lua环境安装
- (OK) C/S—心跳检测—heartbeat
- java中的缓存技术该如何实现
- 遗产
- batman-adv-kernel-android-(make-depmod-modprobe)
- 抑郁
- springmvc+mybatis学习笔记(汇总)
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
潇铭 医流武神
蓝峰狂龙 潇铭
医流武神 潇铭
潋
潋紫沫作品
慕清潋
潋怎么读
潋紫沫
水潋青绡锦衣染
慕清潋作品
颜紫潋作品
潋的拼音
潋滟
潋滟怎么读
潋滟读音
凰歌潋滟
潋滟意思
潋滟的拼音
潋滟流光
潋滟生香
潋滟天下
潋滟的发音
潋滟怎么读音
潋滟是什么意思
潋滟的意思是什么
水光潋滟晴方好的意思
水光潋滟的意思
湖光潋滟晴方好
红楼之水光潋滟 林林爱菊花茶
潘多拉之翼 潋滟三生
汉宫潋滟 花月夜
水光潋滟晴方好全诗
水光潋滟晴方好下一句
错占君心 晴波潋滟
潍
潍v
潍怎么读
潍水风情湿地公园旅游
潍莱高铁
潍烟高铁
广潍即时拍