Looyao's Blog

记录一些点滴

阻塞socket的读写超时

| Comments

阻塞socket读写是否会永远阻塞在read, write函数调用而不返回? 答案是肯定的, 可能平时写本地测试很难发现这种情况或者模拟出来这种情况. 但是在公网中, 这种情况出现的几率就不会少, 假如服务端主动close掉连接, 网络情况不好导致FIN或者ACK包丢失, 那么客户端永远获知不到连接是否断掉, 那么如果正在执行read调用就会一直阻塞住, 随之而来的是整个进程阻塞住了. 记得刚接手激动网的视频CDN的时候, 就遇到了这个问题, 他们原来写的文件同步程序经常不工作了, 很多视频文件都不能及时同步, 导致源的压力很大, 运维的同学迫切想快点解决这个问题, 不然很难监控, 或者定时kill掉程序重新启动, 囧…看源代码发现使用阻塞的socket而没有一个针对读写的超时控制, 程序挂住的时候strace发现也是卡在了read, 所以, 加个超时时间就解决问题了, 几行代码而已.

connect最好也要设置超时时间, 之前的文章有写过(C socket: 关于connect超时设置), 读写超时可以直接使用setsockopt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define TIMEOUT 30  /* 设置超时时间为30秒 */

struct timeval tv_timeout;
tv_timeout.tv_sec = TIMEOUT;
tv_timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (void *) &tv_timeout, sizeof(struct timeval)) < 0) {
    close(sockfd);
    return -1;
}
tv_timeout.tv_sec = TIMEOUT;
tv_timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv_timeout, sizeof(struct timeval)) < 0) {
    close(sockfd);
    return -1;
}

这个超时是具体是什么意思呢? 具体就是在超时时间内没有收到任何数据, 那么read/write就会返回.

当然还有很多其他方法解决这种问题, 比如使用非阻塞socket, 或者使用poll, select. 不过这种方法已经解决掉了进程会卡住的情况.

Comments