您的位置:首页 > 理论基础 > 计算机网络

TCP检测连接非正常中断

2010-07-25 14:39 260 查看

http://blog.201314.info/tag/so_sndtimeo

在维护检测TCP的正常连接方面 SOL_SOCKET类提供了

SO_KEEPALIVE 保持连接 int

SO_RCVTIMEO 接收超时 struct timeval

SO_SNDTIMEO 发送超时 struct timeval

SOL_TCP类提供了

TCP_KEEPIDLE /*开始首次KeepAlive探测前的TCP空闭时间 */

TCP_KEEPINTVL /* 两次KeepAlive探测间的时间间隔 */

TCP_KEEPCNT /* 判定断开前的KeepAlive探测次数 */

上面的几个SOCKET属性是用来检测连接情况和传送接受属性的,但是在不停发包的情况下是不能使用的,不是说是TCP的缺陷,而是他设计的初衷就是为了维护短暂的中断的连接。 在已经连接上以后,不间断的发包会使得TCP的连接状态维持在ESTABLISHED上。

你可以在你的代码里面使用alarm函数,每隔几秒种发包,中间拔开网线然后用 netstat -t 来查看TCP的连接状况:

Active Internet connections (w/o servers)

Proto Recv-Q Send-Q Local Address Foreign Address State

tcp 0 0 192.168.10.22:5300 192.168.10.62:3117 ESTABLISHED

同样即使你发现网线拨开以后机子发送了几个ARP的查询包,很不幸的告诉你,即使没有收到ARP的查询回复包。在ARP Entry里面该mac地址然后不会被老化。

cat /proc/net/arp

IP address HW type Flags HW address Mask Device

192.168.10.1 0×1 0×2 00:19:E0:DD:41:18 * eth1

192.168.10.62 0×1 0×2 00:16:76:CC:1D:4E * eth1

如果你不想使用《UNIX 网络编程第1卷》上介绍的心博函数(因为需要客户端也要支持),你可以使用两个方法。这两种方法都属于非常规做法,希望各位在使用之前务必清楚TCP连接中会发生什么情况,返回什么样的错误号。

第一种:

Linux平台下,可以通过在connect之前设置SO_SNDTIMO来达到控制连接超时的目的。简单的写了份测试代码:

#include <stdlib.h>

#include <stdio.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <errno.h>
int main(int argc, char *argv[])

{

int fd;

struct sockaddr_in addr;

struct timeval timeo = {3, 0};

socklen_t len = sizeof(timeo);

fd = socket(AF_INET, SOCK_STREAM, 0);

if (argc == 4)

timeo.tv_sec = atoi(argv[3]);

setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);

addr.sin_family = AF_INET;

addr.sin_addr.s_addr = inet_addr(argv[1]);

addr.sin_port = htons(atoi(argv[2]));

if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {

if (errno == EINPROGRESS) {

fprintf(stderr, "timeout/n");

return -1;

}

perror("connect");

return 0;

}

printf("connected/n");

return 0;

}

端口号使用原来连接的端口号去检测可以保证测试到对端的程序是否正常工作,使用广泛的端口号只能保证对端的主机是否存活。

第二种:

删除Arp地址,通过检测是否能够再次获得对端mac地址来判断对方是否存活。缺点是不能跨越路由器,同样不能检测可以保证测试到对端的程序是否正常工作:

#include

<sys/ioctl.h>

#include

<sys/socket.h>

#include

<net/if.h>

#include

<netinet/if_ether.h>

int get_arp(unsigned int ip)

{

int sd;

struct arpreq arpreq;

struct sockaddr_in *sin;

struct in_addr ina;

unsigned char *hw_addr;

int rc;

sd = socket(AF_INET, SOCK_DGRAM, 0);

if (sd < 0)

{

perror(“socket() error/n”);

exit(1);

}

/* Try to find an entry in arp cache for the ip address specified */

printf(“Find arp entry for IP : %s/n”, ip);

memset(&arpreq, 0, sizeof(struct arpreq));

sin = (struct sockaddr_in *) &arpreq.arp_pa;

memset(sin, 0, sizeof(struct sockaddr_in));

sin->sin_family = AF_INET;

ina.s_addr = ip;//inet_addr(ip);

memcpy(&sin->sin_addr, (char *)&ina, sizeof(struct in_addr));

strcpy(arpreq.arp_dev, “eth1″);

rc = ioctl(sd, SIOCGARP, &arpreq);

return rc;

}

int del_arp(unsigned int ip)

{

int sd;

struct arpreq arpreq;

struct sockaddr_in *sin;

struct in_addr ina;

unsigned char *hw_addr;

int rc;

sd = socket(AF_INET, SOCK_DGRAM, 0);

if (sd < 0)

{

perror(“socket() error/n”);

exit(1);

}

/* Try to find an entry in arp cache for the ip address specified */

printf(“Find arp entry for IP : %s/n”, ip);

memset(&arpreq, 0, sizeof(struct arpreq));

sin = (struct sockaddr_in *) &arpreq.arp_pa;

memset(sin, 0, sizeof(struct sockaddr_in));

sin->sin_family = AF_INET;

ina.s_addr = ip;//inet_addr(ip);

memcpy(&sin->sin_addr, (char *)&ina, sizeof(struct in_addr));

strcpy(arpreq.arp_dev, “eth1″);

rc = ioctl(sd, SIOCDARP, &arpreq);

return rc;

}

这样的方法比较简单,不要浪费资源。 用connect的在比较多的连接方面判断起来还是比较吃力的,但是它可以跨越路由器。

一般的情况在没有必要检测TCP的连接状态,主要是从TCP的机制考虑的,他的设计初衷就是为了保证间断的连接。但是在一些BT的系统中TCP系统实现的并不完善,需要这样辅助的手段保证对方重新使用新的端口重新连接。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: