我们都知道connect函数执行TCP协议中的三次握手过程,在默认情况下,connect是阻塞的。
当通过tcp客户端向未知ip发起connect请求时,tcpdump抓包情况:
21:13:15.545917 IP 192.168.237.128.57368 > 144.34.160.165.16clouds.com.12345: Flags [S], seq 287971294, win 29200, options [mss 1460,sackOK,TS val 3553264049 ecr 0,nop,wscale 7], length 0
21:13:16.550200 IP 192.168.237.128.57368 > 144.34.160.165.16clouds.com.12345: Flags [S], seq 287971294, win 29200, options [mss 1460,sackOK,TS val 3553265054 ecr 0,nop,wscale 7], length 0
21:13:18.566704 IP 192.168.237.128.57368 > 144.34.160.165.16clouds.com.12345: Flags [S], seq 287971294, win 29200, options [mss 1460,sackOK,TS val 3553267070 ecr 0,nop,wscale 7], length 0
21:13:22.599110 IP 192.168.237.128.57368 > 144.34.160.165.16clouds.com.12345: Flags [S], seq 287971294, win 29200, options [mss 1460,sackOK,TS val 3553271103 ecr 0,nop,wscale 7], length 0
21:13:30.790961 IP 192.168.237.128.57368 > 144.34.160.165.16clouds.com.12345: Flags [S], seq 287971294, win 29200, options [mss 1460,sackOK,TS val 3553279294 ecr 0,nop,wscale 7], length 0
21:13:36.548172 IP 144.34.160.165.16clouds.com.12345 > 192.168.237.128.57368: Flags [R.], seq 414153142, ack 287971295, win 64240, length 0
可见,在整个connect阻塞过程中,客户端会不断重启SYN报文的发送,发送间隔逐渐增大,大约在20s后connect才超时退出。
当网络连接数量巨大是,阻塞的connect会导致效率非常低下。我们可以采用以下两种方式来设置其超时时间。
信号中断方式
在调用connect()前,调用alarm()设置一个超时值,在指定时间后产生SIGALARM信号,中断可能阻塞的connect。
我们采用sigaction()来实现信号处理函数signal(),设置SIGALARM信号中断的系统调用为不自动重启,这样才能达到超时退出的目的。
typedef void Sigfunc (int);
static void connect_sigfun(int signo)
{
return;
}
Sigfunc* signal(int signo, Sigfunc * func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigempty