Chinaunix首页 | 论坛 | 博客
  • 博客访问: 649703
  • 博文数量: 780
  • 博客积分: 10000
  • 博客等级: 上将
  • 技术积分: 4885
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-22 16:14
文章分类

全部博文(780)

文章存档

2008年(780)

我的朋友

分类: LINUX

2008-08-22 16:19:41


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

SO_KEEPALIVE保持连接int
SO_RCVTIMEO接收超时structtimeval
SO_SNDTIMEO发送超时structtimeval

SOL_TCP类提供了

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

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

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

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

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

ActiveInternetconnections(w/oservers)
ProtoRecv-QSend-QLocalAddress ForeignAddress State
tcp 0 0192.168.10.22:5300 192.168.10.62:3117 ESTABLISHED

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

cat/proc/net/arp

IPaddress HWtype Flags HWaddress Mask Device
192.168.10.1 0x1 0x2 00:19:E0:DD:41:18 * eth1
192.168.10.62 0x1 0x2 00:16:76:CC:1D:4E * eth1

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

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


#include
#include
#include
#include
#include
#include

intmain(intargc,char*argv[])
{
intfd;
structsockaddr_inaddr;
structtimevaltimeo={3,0};
socklen_tlen=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,(structsockaddr*)&addr,sizeof(addr))==-1){
if(errno==EINPROGRESS){
fprintf(stderr,"timeout\n");
return-1;
}
perror("connect");
return0;
}
printf("connected\n");

return0;
}


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

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

#include
#include
#include
#include

intget_arp(unsignedintip)
{
intsd;

structarpreqarpreq;
structsockaddr_in*sin;
structin_addrina;
unsignedchar*hw_addr;

intrc;

sd=socket(AF_INET,SOCK_DGRAM,0);
if(sd<0)
{
perror("socket()error\n");
exit(1);
}

/*Trytofindanentryinarpcachefortheipaddressspecified*/

printf("FindarpentryforIP:%s\n",ip);

memset(&arpreq,0,sizeof(structarpreq));
sin=(structsockaddr_in*)&arpreq.arp_pa;
memset(sin,0,sizeof(structsockaddr_in));
sin->sin_family=AF_INET;
ina.s_addr=ip;//inet_addr(ip);
memcpy(&sin->sin_addr,(char*)&ina,sizeof(structin_addr));

strcpy(arpreq.arp_dev,"eth1");

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

returnrc;
}


intdel_arp(unsignedintip)
{
intsd;

structarpreqarpreq;
structsockaddr_in*sin;
structin_addrina;
unsignedchar*hw_addr;

intrc;

sd=socket(AF_INET,SOCK_DGRAM,0);
if(sd<0)
{
perror("socket()error\n");
exit(1);
}

/*Trytofindanentryinarpcachefortheipaddressspecified*/

printf("FindarpentryforIP:%s\n",ip);

memset(&arpreq,0,sizeof(structarpreq));
sin=(structsockaddr_in*)&arpreq.arp_pa;
memset(sin,0,sizeof(structsockaddr_in));
sin->sin_family=AF_INET;
ina.s_addr=ip;//inet_addr(ip);
memcpy(&sin->sin_addr,(char*)&ina,sizeof(structin_addr));

strcpy(arpreq.arp_dev,"eth1");

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



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

一般的情况在没有必要检测TCP的连接状态,主要是从TCP的机制考虑的,他的设计初衷就是为了保证间断的连接。但是在一些BT的系统中TCP系统实现的并不完善,需要这样辅助的手段保证对方重新使用新的端口重新连接。
下载本文示例代码
阅读(382) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~