WSAWaitForMultipleEvents、資料少ない…。動くことは動いたけど、終了処理が怪しいなぁ。
#include <stdio.h> #include <winsock2.h> #define _CRT_SECURE_DEPRECATE_MEMORY #include <memory.h> #define ECHO_PORT 7 #define MAX_BACKLOG 5 #define WSAWFME_TIMEOUT 1000 #define RCVBUFSIZE 256 #define die(...) do { fprintf(stderr, __VA_ARGS__); WSACleanup(); exit(1); } while(0) #define error(...) do { fprintf(stderr, __VA_ARGS__); } while(0) static void wsa_startup(WORD version) { int n; WSADATA wsaData; if ((n = WSAStartup(version, &wsaData)) != 0) { die("WASStartup(): %d\n", n); } if (version != wsaData.wVersion) { die("WASStartup(): WinSock version %d.%d not supported\n", LOWORD(version), HIWORD(version)); } } int echo(SOCKET sock) { char buf[RCVBUFSIZE + 1]; size_t len; if ((len = recv(sock, buf, RCVBUFSIZE, 0)) < 0) { error("recv(): %d\n", WSAGetLastError()); return -1; } if (len == 0) { return 0; } buf[len] = '\0'; error("recv: %d '%s'\n", sock, buf); if (send(sock, buf, len, 0) < 0) { error("send(): %d\n", WSAGetLastError()); return -1; } return len; } int main() { int i; SOCKET sock; SOCKET sockets[WSA_MAXIMUM_WAIT_EVENTS]; HANDLE hEvents[WSA_MAXIMUM_WAIT_EVENTS]; struct sockaddr_in addr; wsa_startup(MAKEWORD(2, 0)); if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { die("socket(): %d\n", WSAGetLastError()); } addr.sin_family = AF_INET; addr.sin_port = htons(ECHO_PORT); addr.sin_addr.S_un.S_addr = INADDR_ANY; if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) != 0) { die("bind(): %d\n", WSAGetLastError()); } if (listen(sock, MAX_BACKLOG) != 0) { die("listen(): %d\n", WSAGetLastError()); } memset(sockets, 0, sizeof(sockets)); memset(hEvents, 0, sizeof(sockets)); sockets[0] = sock; hEvents[0] = WSACreateEvent(); if (WSAEventSelect(sock, hEvents[0], FD_ACCEPT) < 0) { die("WSAEventSelect(): %d\n", WSAGetLastError()); } while(1) { DWORD n, cEvents = 0; SOCKET fd, _sockets[WSA_MAXIMUM_WAIT_EVENTS]; HANDLE hEvent, _hEvents[WSA_MAXIMUM_WAIT_EVENTS]; WSANETWORKEVENTS events; int j; for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { if (hEvents[i]) { _sockets[cEvents] = sockets[i]; _hEvents[cEvents] = hEvents[i]; cEvents++; } } switch(n = WSAWaitForMultipleEvents(cEvents, hEvents, FALSE, WSAWFME_TIMEOUT, FALSE)) { case WSA_WAIT_TIMEOUT: continue; case WSA_WAIT_FAILED: die("WSAWaitForMultipleEvents(): %d\n", WSAGetLastError()); } fd = _sockets[n - WSA_WAIT_EVENT_0]; hEvent = _hEvents[n - WSA_WAIT_EVENT_0]; if (WSAEnumNetworkEvents(fd, hEvent, &events) < 0) { die("WSAEnumNetworkEvents(): %d\n", WSAGetLastError()); } if (events.lNetworkEvents & FD_ACCEPT) { SOCKET s; struct sockaddr_in caddr; int len = sizeof(caddr); if ((s = accept(fd, (struct sockaddr *) &caddr, &len)) == INVALID_SOCKET) { error("accept(): %d\n", WSAGetLastError()); } error("accepted: %d\n", s); for (j = 0; j < WSA_MAXIMUM_WAIT_EVENTS; j++) { if (!hEvents[j]) { sockets[j] = s; hEvents[j] = WSACreateEvent(); if (WSAEventSelect(s, hEvents[j], FD_READ | FD_CLOSE) < 0) { die("WSAEventSelect(): %d\n", WSAGetLastError()); } break; } } if (j >= WSA_MAXIMUM_WAIT_EVENTS) { closesocket(s); } } else if (events.lNetworkEvents & FD_READ) { if (echo(fd) < 1) { for (j = 0; j < WSA_MAXIMUM_WAIT_EVENTS; j++) { if (sockets[j] == fd) { sockets[j] = INVALID_SOCKET; hEvents[j] = NULL; break; } } if (WSAEventSelect(fd, NULL, 0) < 0) { die("WSAEventSelect(): %d\n", WSAGetLastError()); } WSACloseEvent(hEvent); closesocket(fd); error("closed: %d\n", fd); } } else if (events.lNetworkEvents & FD_CLOSE) { for (j = 0; j < WSA_MAXIMUM_WAIT_EVENTS; j++) { if (sockets[j] == fd) { sockets[j] = INVALID_SOCKET; hEvents[j] = NULL; break; } } if (WSAEventSelect(fd, NULL, 0) < 0) { die("WSAEventSelect(): %d\n", WSAGetLastError()); } WSACloseEvent(hEvent); closesocket(fd); error("closed: %d\n", fd); } } if (WSAEventSelect(sock, NULL, 0) < 0) { die("WSAEventSelect(): %d\n", WSAGetLastError()); } WSACloseEvent(hEvents[0]); closesocket(sock); WSACleanup(); return 0; }