こんな感じ。
#include <stdio.h> #include <winsock2.h> #include "wspoll.h" #include <memory.h> #define ECHO_PORT 7 #define MAX_BACKLOG 5 #define RCVBUFSIZE 256 #define MAX_NFDS WSA_MAXIMUM_WAIT_EVENTS #define POLL_TIMEOUT 1000 #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[MAX_NFDS]; 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)); for (i = 0; i < MAX_NFDS; i++) { sockets[i] = INVALID_SOCKET; } sockets[0] = sock; while(1) { int i, j, nfds = 0; struct sockaddr_in sa; size_t len = sizeof(sa); struct pollfd pollfds[MAX_NFDS]; for (i = 0; i < MAX_NFDS; i++) { if (sockets[i] != INVALID_SOCKET) { pollfds[nfds].fd = sockets[i]; pollfds[nfds].events = POLLIN; nfds++; } } switch (poll(pollfds, nfds, POLL_TIMEOUT)) { case 0: continue; case -1: die("poll(2)\n"); } for (i = 0; i < nfds; i++) { int fd = pollfds[i].fd; if (!(pollfds[i].revents & POLLIN)) { continue; } if (sock == fd) { int s; if ((s = accept(sock, (struct sockaddr*) &sa, &len)) < 0) { die("accept(2)\n"); } error("accepted.\n"); for (j = 0; j < MAX_NFDS; j++) { if (sockets[j] == INVALID_SOCKET) { sockets[j] = s; break; } } if (j >= MAX_NFDS) { closesocket(s); } } else { if (echo(fd) < 1) { closesocket(fd); sockets[i] = INVALID_SOCKET; } } } } closesocket(sock); WSACleanup(); return 0; }
wspoll.h
#include <winsock2.h> #ifndef _WSPOLL_H_ #define _WSPOLL_H_ #ifdef POLLRDNORM #undef POLLRDNORM #undef POLLRDBAND #undef POLLIN #undef POLLPRI #undef POLLWRNORM #undef POLLOUT #undef POLLWRBAND #undef POLLERR #undef POLLHUP #undef POLLNVAL struct _pollfd { SOCKET fd; short events; short revents; }; #define pollfd _pollfd #else struct pollfd { SOCKET fd; short events; short revents; }; #endif typedef unsigned int nfds_t; #define POLLIN (FD_READ | FD_ACCEPT | FD_CLOSE) #define POLLPRI (FD_OOB) #define POLLOUT (FD_WRITE | FD_CONNECT | FD_CLOSE) #define POLLRDHUP (FD_CLOSE) #define POLLHUP (FD_CLOSE) #define POLLRDNORM (POLLIN) #define POLLRDBAND (POLLIN | POLLPRI) #define POLLWRNORM (POLLOUT) #define POLLWRBAND (POLLOUT | POLLPRI) // POLLERR, POLLNVAL not defined int poll(struct pollfd *fds, nfds_t nfds, int timeout); #endif
wspoll.c
#include <malloc.h> #include <errno.h> #include "wspoll.h" static int init(struct pollfd *pollfds, nfds_t nfds, SOCKET *fds, HANDLE *hEvents) { nfds_t i; for (i = 0; i < nfds; i++) { fds[i] = INVALID_SOCKET; hEvents[i] = NULL; } for (i = 0; i < nfds; i++) { fds[i] = pollfds[i].fd; hEvents[i] = WSACreateEvent(); pollfds[i].revents = 0; if (WSAEventSelect(fds[i], hEvents[i], pollfds[i].events) < 0) { errno = WSAGetLastError(); return -1; } } return 0; } static void clean(nfds_t nfds, SOCKET *fds, HANDLE *hEvents) { nfds_t i; for (i = 0; i < nfds; i++) { if (fds[i] != INVALID_SOCKET) { WSAEventSelect(fds[i], NULL, 0); } if (hEvents[i] != NULL) { WSACloseEvent(hEvents[i]); } } } int poll(struct pollfd *pollfds, nfds_t nfds, int timeout) { SOCKET *fds; HANDLE *hEvents; DWORD n; fds = alloca(sizeof(SOCKET) * nfds); hEvents = alloca(sizeof(HANDLE) * nfds); if (init(pollfds, nfds, fds, hEvents) < 0) { clean(nfds, fds, hEvents); return -1; } n = WSAWaitForMultipleEvents(nfds, hEvents, FALSE, timeout, FALSE); if (n == WSA_WAIT_FAILED) { clean(nfds, fds, hEvents); return -1; } else if (n == WSA_WAIT_TIMEOUT) { clean(nfds, fds, hEvents); return 0; } else { SOCKET fd; HANDLE hEvent; WSANETWORKEVENTS events; n -= WSA_WAIT_EVENT_0; fd = fds[n]; hEvent = hEvents[n]; if (WSAEnumNetworkEvents(fd, hEvent, &events) < 0) { clean(nfds, fds, hEvents); return -1; } pollfds[n].revents = (short) events.lNetworkEvents; clean(nfds, fds, hEvents); return n + 1; } }