呼叫 connect() 嘗試建立完整三向交握:
優點:無需原始套接字權限,普通使用者即可執行。缺點:日誌明顯,易被 IDS 捕獲。
主執行緒 (UI)
│
▼
StartScan 執行緒 (生產者)
├─ 依範圍/指定埠建立 DoScanPort 執行緒
├─ 控制並發上限 (g_nMaxThread = 200)
└─ 等待所有掃描執行緒結束
│
▼
DoScanPort 執行緒 (消費者, 每埠一個)
├─ socket() + ioctlsocket(FIONBIO) 非阻塞
├─ connect() 發起
├─ select() 監聽寫就緒,超時 g_dwTimeOut (預設 1000ms)
├─ 發送 WM_COPYDATA 回主視窗更新結果
└─ 原子遞減 g_nThreadCount
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
u_long flag = 1; ioctlsocket(sock, FIONBIO, &flag); // 非阻塞
sockaddr_in sa = {AF_INET, htons(port), inet_addr(targetIP)};
connect(sock, (sockaddr*)&sa, sizeof(sa)); // 立即返回
fd_set wset; FD_ZERO(&wset); FD_SET(sock, &wset);
timeval tv = {timeout/1000, timeout%1000};
int ret = select(0, NULL, &wset, NULL, &tv);
if (ret == 1 && FD_ISSET(sock, &wset)) {
int err = 0; int len = sizeof(err);
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
if (err == 0) // 連線成功
SendMessage(hWnd, ..., PORT_OPEN, port);
}
closesocket(sock);
// StartScan 中
while (g_nThreadCount >= g_nMaxThread) Sleep(10);
if (CreateThread(..., &tid)) InterlockedIncrement(&g_nThreadCount);
// DoScanPort 結束
InterlockedDecrement(&g_nThreadCount);
| 參數 | 測試值 | 建議 |
|---|---|---|
| 最大執行緒 | 200 | 過高導致調度開銷反而降速;依 CPU 核心與網路帶寬調整 |
| 超時時間 | 1000ms | 區網 200-500ms;跨公網 1000-3000ms。過短誤判率升高 |
| 掃描速度 | ~150 ports/sec | 受限於 TCP 交握 RTT 與 select 精度 |
未經授權掃描他人主機屬違法行為。本程式僅供教學、授權滲透測試與自有資產盤點使用。
多執行緒非阻塞模型在簡單易懂與效能之間取得平衡。理解 select 邊緣觸發行為、執行緒池背壓控制、超時與準確率的權衡,是編寫高品質掃描器的關鍵。