1. 程式人生 > >accept與connect的超時設定

accept與connect的超時設定

connect超時:

我們都知道,connect對應與三次握手中的第一次傳送SYN,而對待伺服器的ACK,如果伺服器沒有啟動伺服器,有些機器會立刻返回一個RST表示伺服器拒絕,從而connect失敗,但又些伺服器為了防止攻擊,什麼也不傳送,直至客戶端connect超時,而這一時間又75s,對於客戶端來說是不能接收的。所以需要設定connect的超時時間。

利用select設定connect的超時時間:

<span style="white-space:pre">	</span>uint32_t ul = 1;
	ioctl(sock, FIONBIO, &ul);//設定成非阻塞
	printf("start time: %u\n", time(0));
	bool success = false;
	if (connect(sock, (sockaddr *)&srv_addr, sizeof srv_addr ) == -1)
	{
<span style="white-space:pre">		</span>struct timeval tm;
		tm.tv_sec = 3;
		tm.tv_usec = 0;
<span style="white-space:pre">		</span>fd_set set;
		FD_ZERO(&set);
		FD_SET(sock, &set);
		if (select(sock + 1, NULL, &set, NULL, &tm) > 0)
		{
			int error = 0;
			int len = sizeof(int);
			getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
			if (0 == error) success = true;
		}
		else
		{
			success = false;
		}
	}
	ul = 0;
	ioctl(sock, FIONBIO, &ul); //設定成阻塞

accept超時:

一半來說伺服器應該都是在accept狀態,也就無需設定accept超時時間,但一些特殊情況還是需要的。對於accept我們可以使用select多路複用來實現超時設定,但那個程式碼較多。那有沒有別的辦法呢?我們指定,accept對應三次握手中中伺服器接收SYN,那麼我們能不能通過設定recv超時來實現accept超時呢?答案是肯定的。

struct timeval timeout = {6,0};
if (setsockopt(proxy_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval)) != 0)
{
	printf("set accept timeout failed");
}
sock = ::accept(proxy_sock, (sockaddr *)NULL, NULL);

既然可以用recv超時來設定accept超時,那對於connect能不能通過設定send超時來實現connect超時呢?答案是肯定的!!!
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
只要將connect和accept對應到三次握手過程中就不難理解這些了。

綜上:

我們可以通過設定SO_RECVTIMEO和SO_SENDTIMEO來設定accept超時和connect超時。