一.背景
最近在專案中需要高效率的掃瞄出各個伺服器開放了哪些埠,第一反應是用ping去做,而ping是能檢測網路連通性,不能判斷是否開放了埠。埠屬於osi七層模型中的傳輸層,因此需要使用ip+埠來實現,所以使用connect來實現。針對tcp協議,connect函式要進行tcp三次握手,如果connect成功,則說明伺服器開放了某個埠,如果connect失敗,則說明伺服器沒有開放某個埠。而connect失敗是通過超時來控制的,在規定的時間內,connect會發起多次連線,一直執行到超時,才返回錯誤。預設情況下,connect是阻塞的,而且預設的超時時間為75s,正常情況下,檢測網路的連通性都是毫秒級,如果要判斷10萬台伺服器的,用阻塞的預設的connect去做,效率非常低下。因此採用非阻塞的connect,而且需要自定義超時間(我自定義超時時間為5s)。
2、非阻塞connect
對於阻塞式套接字,呼叫connect函式將激發tcp的三次握手過程,而且僅在連線建立成功或者出錯時才返回;對於非阻塞式套接字,如果呼叫connect函式會之間返回-1(表示出錯),且錯誤為einprogress,表示連線建立,建立啟動但是尚未完成;如果返回0,則表示連線已經建立,這通常是在伺服器和客戶在同一臺主機上時發生。
select是一種io多路復用機制,它允許程序指示核心等待多個事件的任何乙個發生,並且在有乙個或者多個事件發生或者經歷一段指定的時間後才喚醒它。connect本身並不具有設定超時功能,如果想對套接字的io操作設定超時,可使用select函式。
對於select和非阻塞connect,注意兩點:[1] 當連線成功建立時,描述符變成可寫; [2] 當連線建立遇到錯誤時,描述符變為即可讀,也可寫,遇到這種情況,可呼叫getsockopt函式。
3、實現步驟
(1) 建立socket,並利用fcntl將其設定為非阻塞
(2) 呼叫connect函式,如果返回0,則連線建立;如果返回-1,檢查errno ,如果值為 einprogress,則連線正在建立。
(3) 為了控制連線建立時間,將該socket描述符加入到select的可讀可寫集合中,採用select函式設定超時。
(4) 如果規定時間內成功建立,則描述符變為可寫;否則,採用getsockopt函式捕獲錯誤資訊
(5) 恢復套接字的檔案狀態並返回。
測試**如下所示:
#include
#include
#include
#include
#include
/* see notes */
#include
#include
#include
#include
intmain
(int argc,
char
**ar**)
char
*ipaddr = ar**[1]
;unsigned
int port =
atoi
(ar**[2]
);int fd =0;
struct sockaddr_in addr;
fd_set fdr, fdw;
struct timeval timeout;
int err =0;
int errlen =
sizeof
(err)
; fd =
socket
(af_inet,sock_stream,0)
;if(fd <0)
bzero
(&addr,
sizeof
(addr));
addr.sin_family = af_inet;
addr.sin_port =
htons
(port)
;inet_pton
(af_inet, ipaddr,
&addr.sin_addr)
;/*設定套接字為非阻塞*/
int flags =
fcntl
(fd, f_getfl,0)
;if(flags <0)
flags |
= o_nonblock;if(
fcntl
(fd, f_setfl, flags)
<0)
/*阻塞情況下linux系統預設超時時間為75s*/
int rc =
connect
(fd,
(struct sockaddr*
)&addr,
sizeof
(addr));
if(rc !=0)
/*連線超時*/
if(rc ==0)
/*[1] 當連線成功建立時,描述符變成可寫,rc=1*/
if(rc ==1&&
fd_isset
(fd,
&fdw)
)/*[2] 當連線建立遇到錯誤時,描述符變為即可讀,也可寫,rc=2 遇到這種情況,可呼叫getsockopt函式*/
if(rc ==2)
if(err)}}
fprintf
(stderr
,"connect failed, error:%s.\n"
,strerror
(errno));
return-1
;}return0;
}
linux網路程式設計之udp的connect趣談
對於linux網路程式設計,udp協議不是面向連線的協議,直接把資料報傳送到鏈路層,至於能不能到達目的ip和埠,它不關注 大部分時候再編寫 時候只需要在sendto函式中指定你要傳送的埠和ip位址就可以了,不用繫結ip和埠。不過你是否考慮過,udp到底是否可以進行connect,如果對udp進行co...
網路程式設計之Socket程式設計
對 tcp ip udp socket 程式設計這些詞你不會很陌生吧?隨著網路技術的發展,這些詞充斥著我們的耳朵。那麼我想問 1.什麼是tcp ip udp?2.socket在 呢?3.socket是什麼呢?4.你會使用它們嗎?什麼是tcp ip udp?tcp ip transmission co...
網路程式設計之socket程式設計
大多數專案是在linux下開發伺服器端,而在windows下開發客戶端,需要經常在兩大平台之間進行切換,單獨學習一種平台沒有實踐意義。值得欣慰的是,兩大平台下的 socket 程式設計非常相似,並不會增加多少學習成本。網路程式設計就是編寫程式使兩台聯網的計算機相互交換資料。這就是socket的全部內...