linux下TCP通讯相关问题:select控制数据收发 对网络异常情况(如拔网线)的处理 停止程序后如何能快速再次bind

工作中用到了TCP通讯,把遇到的问题和解决方法小结一下,方便以后查阅,有问题的地方也请各位大神指出~


问题一:非阻塞收发

    按照最初的想法,我是想用setsockopt()设置下收发的阻塞时间间隔就OK了,可是通讯时状况百出,也没搞清楚为什么这样不对,如果有哪位大神能指点一下,小弟感激不尽,错误代码这里就不粘了,省得误人子弟~

         最终我采用的方法是select判断收发缓冲区,已经过验证,下面付一小段代码:

接收端:

while(1)
{
<span style="white-space:pre">	</span>FD_ZERO(&serialread);
<span style="white-space:pre">	</span>FD_SET(sock,&serialread);
	serialtimeout.tv_sec = 0;
	serialtimeout.tv_usec = 500000;
	switch(select(g_sock+1,&serialread,NULL,NULL,&serialtimeout))
	{
	case -1:
		perror("select error----");
		return;
	break;
	case 0:
	{
		continue;
	}
	break;
	default:
	{
		if(FD_ISSET(g_sock,&serialread))
				sign_read = 1;
	}
		break;
	}
	if(sign_read != 1)
		continue;
	sign_read = 0;
<span style="white-space:pre">	</span>buflen = recv(sock,recvbuf,MAX_DATA_LEN,0);
<span style="white-space:pre">	</span>if (buflen < 0 && errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>perror("Net link error,close the link!---");
<span style="white-space:pre">		</span>close(g_sock);
<span style="white-space:pre">		</span>break;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>else if(buflen==0 || errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN)
<span style="white-space:pre">		</span>continue;
<span style="white-space:pre">	</span>else if(buflen < IEC104_U_FRAME_LEN)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>tcflush(sock,TCIFLUSH);
<span style="white-space:pre">		</span>continue;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>/*数据处理*/
}
发送端是同样的道理。

问题二:对连接异常的判断和处理

              开发时我的需求是满足网线的热插拔,就是设备不断电的情况下网线拔掉再插上还能继续通讯(前提:我做的是TCP server端,client端是第三方软件),对于linux底层对网络连接的状态判断,我在网上查了些资料,下面是链接:

http://blog.csdn.net/ctthuangcheng/article/details/8596818

http://bbs.csdn.net/topics/40417156

               我的解决方法也就是上面第二个链接中一位大神介绍的方法,就是在创建socket后设置keepalive的时间间隔:

int param = 1;
struct linger lingerStruct;
<span style="white-space:pre">	</span>lingerStruct.l_onoff = 1;
<span style="white-space:pre">	</span>lingerStruct.l_linger = 0;
if(0 != setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char*)&param,sizeof(param)))//设置tcp心跳包的间隔时间
<span style="white-space:pre">	</span>perror("Set tcp keepalive time error---");
if(0 != setsockopt(transmit_pthread,SOL_SOCKET, SO_LINGER,(char *)&lingerStruct, sizeof(lingerStruct)))//设置close()函数立即生效
	perror("Set tcp linger error---");
              需要注意的是,linux系统把默认的tcp心跳包时间间隔设置为7200s是为了不占用网络资源,因此网络通讯数据量很大或者对实时性要求很高的时候建议根据实际情况进行调整

问题三:用CTRL+C停止程序后要等一段时间才能bind成功

              之所以出现这种情况是因为程序停止后原来创建的socket没有立即释放,大概要等1~2min的时间,因此在此时间内再次bind()会失败,解决方法是在创建socket后执行:

int on = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))






 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值