CSocket 封裝了阻塞模式與消息泵,高併發下線程開銷大。原始 Socket + select/WSAEventSelect 可單線程管理萬級並發連接。
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
u_long mode = 1;
ioctlsocket(sock, FIONBIO, &mode); // 設置非阻塞
sockaddr_in addr = {AF_INET, htons(port), inet_addr(ip)};
int ret = connect(sock, (sockaddr*)&addr, sizeof(addr));
if (ret == SOCKET_ERROR) {
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) { closesocket(sock); return; }
// 連接發起中,加入 select 寫集合等待可寫
}
fd_set writeSet;
FD_ZERO(&writeSet);
FD_SET(sock, &writeSet);
timeval tv = {2, 0}; // 2秒超時
if (select(0, NULL, &writeSet, NULL, &tv) > 0 && FD_ISSET(sock, &writeSet)) {
int err = 0; int len = sizeof(err);
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
if (err == 0) { /* 連接成功 */ }
}
closesocket(sock);
std::vector<SOCKET> sockets;
for (port = start; port <= end; ++port) {
SOCKET s = socket(...);
ioctlsocket(s, FIONBIO, &mode);
connect(s, ...); // 發起所有連接
sockets.push_back(s);
}
while (!sockets.empty()) {
fd_set writeSet; FD_ZERO(&writeSet);
for (auto s : sockets) FD_SET(s, &writeSet);
if (select(0, NULL, &writeSet, NULL, &tv) <= 0) break; // 超時
for (auto it = sockets.begin(); it != sockets.end(); ) {
if (FD_ISSET(*it, &writeSet)) {
// 檢查 SO_ERROR 確認結果
it = sockets.erase(it);
} else ++it;
}
}
同 getservbyport 解析知名端口,結果寫入文件或 UI。
見後續博文置頂下載鏈接。