1、前言

  最近在寫一個(gè)測試工具,要求快速的高效率的掃描出各個(gè)服務(wù)器開放了哪些端口。當(dāng)時(shí)想了一下,ping只能檢測ip,判斷服務(wù)器的網(wǎng)絡(luò)是連通的,而不能判斷是否開放了端口。我們知道端口屬于網(wǎng)絡(luò)的傳輸層,因此需要用ip和端口來探測,這個(gè)時(shí)候就可以用connect來探測一下,針對TCP協(xié)議,connect函數(shù)要進(jìn)行TCP三次握手,如果connect成功,則說明服務(wù)器開放了某個(gè)端口,如果connect失敗,則說明服務(wù)器沒有開放某個(gè)端口。而connect失敗是通過超時(shí)來控制的,在規(guī)定的時(shí)間內(nèi),connect會發(fā)起多次連接,一直執(zhí)行到超時(shí),才返回錯(cuò)誤。默認(rèn)情況下,connect是阻塞的,而且默認(rèn)的超時(shí)時(shí)間為75s,正常情況下,檢測網(wǎng)絡(luò)的連通性都是毫秒級,如果要判斷10萬臺服務(wù)器的,用阻塞的默認(rèn)的connect去做,效率非常低下。因此采用非阻塞的connect,而且需要自定義超時(shí)間(我自定義超時(shí)時(shí)間為5s)。

2、非阻塞connect

  對于阻塞式套接字,調(diào)用connect函數(shù)將激發(fā)TCP的三次握手過程,而且僅在連接建立成功或者出錯(cuò)時(shí)才返回;對于非阻塞式套接字,如果調(diào)用connect函數(shù)會之間返回-1(表示出錯(cuò)),且錯(cuò)誤為EINPROGRESS,表示連接建立,建立啟動但是尚未完成;如果返回0,則表示連接已經(jīng)建立,這通常是在服務(wù)器和客戶在同一臺主機(jī)上時(shí)發(fā)生。

  select是一種IO多路復(fù)用機(jī)制,它允許進(jìn)程指示內(nèi)核等待多個(gè)事件的任何一個(gè)發(fā)生,并且在有一個(gè)或者多個(gè)事件發(fā)生或者經(jīng)歷一段指定的時(shí)間后才喚醒它。connect本身并不具有設(shè)置超時(shí)功能,如果想對套接字的IO操作設(shè)置超時(shí),可使用select函數(shù)。

  對于select和非阻塞connect,注意兩點(diǎn):[1] 當(dāng)連接成功建立時(shí),描述符變成可寫; [2] 當(dāng)連接建立遇到錯(cuò)誤時(shí),描述符變?yōu)榧纯勺x,也可寫,遇到這種情況,可調(diào)用getsockopt函數(shù)。

3、實(shí)現(xiàn)步驟

(1) 創(chuàng)建socket,并利用fcntl將其設(shè)置為非阻塞

(2) 調(diào)用connect函數(shù),如果返回0,則連接建立;如果返回-1,檢查errno ,如果值為 EINPROGRESS,則連接正在建立。

(3) 為了控制連接建立時(shí)間,將該socket描述符加入到select的可讀可寫集合中,采用select函數(shù)設(shè)定超時(shí)。

(4) 如果規(guī)定時(shí)間內(nèi)成功建立,則描述符變?yōu)榭蓪懀环駝t,采用getsockopt函數(shù)捕獲錯(cuò)誤信息

(5) 恢復(fù)套接字的文件狀態(tài)并返回。

測試代碼如下所示:

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開發(fā)培訓(xùn)

  1 #include <stdio.h>  2 #include <stdlib.h>  3 #include <string.h>  4 #inc