2.1 设置socket超时

1 背景

写一个c++的TCP通信程序,使用了recv接口。因为该接口默认为阻塞,因此除非检测到连接断开,否则线程会一直阻塞在那里。

现在需要将recv接口增加一个超时,即在n秒内未能recv任何数据,则跳出阻塞。

2 解决方法

解决方法可以有两种:

设置socket接受超时法:recv本身可以设置超时(推荐)。

信号法:recv可以通过信号的方式解除阻塞。

2.1 设置socket超时

在建立连接前增加超时设置:

auto fd = socket(PF_INET, SOCKET_STREAM, 0);

if(-1 == fd){

return "error";

}

// 设置超时

struct timeval timeout = {3, 0}; // 这里设置3秒超时时间

setsocketopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(struct timeval));

if (0 > connect(fd, (struct sockaddr*)&addr_in, sizeof(struct sockaddr))){

return "error";

}

如此就可以在接收不到任何数据后的3秒时间断开阻塞。

2.2 信号法

我们可以利用信号可以解除阻塞的机制进行,就比如我们利用SIGALRM信号,可以使用alarm函数在n秒后触发信号:

#include

void handleSigAlarm(int sign_no){ }

int main(){

struct sigaction alarm_act;

bzero(&alarm_act,sizeof(sigaction));

alarm_act.sa_handler = handleSigAlarm;

alarm_act.sa_flags = SA_NOMASK; // 这里一定是NOMASK

sigaction(SIGALRM,&alarm_act,NULL);

//...

while(true){

alarm(3); // 这里设置3秒超时

auto ret = recv(....)

alarm(0); // 收到后复位

}

}

需要注意的是其中的sa_flags:

如果其值为SA_NOMASK,则会中断已阻塞的函数,使程序继续往下执行,即略过阻塞。

如果其值为SA_RESTART,则会重启函数,也就是会复位继续在recv上阻塞。