linux sock 一个奇怪问题

今天查一个问题,反馈的日志中,看到服务端一个网络套接字sock 被设置成O_NONBLOCK了,但是在read的时候,报错了。

用strerror(errno),打印错误信息,看到是Connection timed out 。


这就诡异了,按理说,设置成O_NONBLOCK了,就不会有time out的,加日志调试的

struct timeval ti;
ti.tv_sec=0;
ti.tv_usec=0;
socklen_t len=sizeof(ti);
getsockopt(rcc->stream->socket,SOL_SOCKET,SO_RCVTIMEO,&ti,&len);


将这里的timeout超时时间也打印出来,看看是不是真有time out大于0那么邪门。调试时发现,这里ti.tv_sec 和 ti.tv_usec都是0。

那这个connect time out是什么意思?哪里报的错误?


从http://blog.csdn.net/u010419967/article/details/24405037,看到

Tcp是面向连接的当tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的响应包),

select会返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT。


这个解释刚好和我们服务端的代码可以对得上。


原来在客户的应用场景,网络延时是比较大的(20ms左右),偶尔还有网络抖动。而且这个tcp连接还没有自己的心跳包,用的是tcp协议默认的心跳。

这个心跳值可以在代码设置,也可以在 /etc/sysctl.conf 设置

      net.ipv4.tcp_keepalive_intvl = 30 这样就可以将该系统上运行的进程,tcp通信的描述为设置默认心跳为30秒。


因为我们的服务器没有配置这个项,所以就用了linux内核的默认值,Linux 2.6.24

#ifndef HZ
#define HZ 100
#endif

#define TCP_KEEPALIVE_INTVL(75*HZ)

所以是 7500秒,2个多小时才发出的一个心跳。在这种网络延时下,经过那么久才检查,tcp检测到对端socket 时,客户端的变成不再可用是很正常不过了。



怎么解决?

在客户端对sock套接字,加入心跳包,频繁一点检查,检查到断开了,就进行重新连接。

    int keepAlive=1;//开启keepalive属性
    int keepIdle=30;//如该连接在30秒内没有任何数据往来,则进行探测
    int keepInterval=2;//探测时发包的时间间隔为2秒
    int keepCount=3;//探测尝试的次数。如果第1次探测包就收到响应了,则后2次的不再发送
    if(setsockopt(_peer,SOL_SOCKET,SO_KEEPALIVE,(void *)&keepAlive,sizeof(keepAlive))!=0)//若无错误发生,setsockopt()返回值为0
    {
        LOG_INFO(" set_keepalive set SO_KEEPALIVE fail");
        return ;
    }
    if(setsockopt(_peer,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle))!=0)
    {
        LOG_INFO("set_keepalive set TCP_KEEPIDLE fail");
        return ;
    }
    if(setsockopt(_peer,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval))!=0)
    {
        LOG_INFO("set_keepalive set TCP_KEEPINTVL fail");
        return ;
    }
    if(setsockopt(_peer,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount))!=0)
    {
        LOG_INFO(" set_keepalive set TCP_KEEPCNT fail");
        return ;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值