accept與connect的超時設定
阿新 • • 發佈:2019-01-04
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超時。