From 2f049101c2601116c29a457f41109328f64bb16d Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Thu, 29 Jan 2026 10:30:41 +0100 Subject: [PATCH] Polling and handling connections + messages at the same time --- src/b.cpp | 84 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/src/b.cpp b/src/b.cpp index 226f8a6..9ad3555 100644 --- a/src/b.cpp +++ b/src/b.cpp @@ -37,6 +37,25 @@ int wrapped_close_socket(SOCKET socket) { return -1; } +void set_non_blocking(SOCKET sock) { + u_long mode = 1; + int err = ioctlsocket(sock, FIONBIO, &mode); + if (err != 0) { + panicf("server: failed to set nonblocking mode %s", wsa_error()); + } +} + +void set_no_delay(SOCKET sock) { + // Disable Nagle's algorithm, this would combine some of the packets together and these would + // get received on server side in one combined buffer. Two stacked 'hello world', the horror! + // This only finally worked when I set it on ALL the sockets, including the one in client. + int nodelay = 0; + int err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); + if (err != 0) { + panicf("server: failed to setsockopt %s", wsa_error()); + } +} + void run_server() { struct addrinfo *infos = {}; struct addrinfo hints = {}; @@ -72,31 +91,62 @@ void run_server() { panicf("server: failed to bind to a port!"); } defer { wrapped_close_socket(sock); }; + set_no_delay(sock); + set_non_blocking(sock); int max_pending_connections = 10; err = listen(sock, max_pending_connections); if (err != 0) { panicf("server: listen failed: %s", wsa_error()); } - sockaddr_storage client_sockaddr = {}; - int sockaddr_len = sizeof(client_sockaddr); - SOCKET client_sock = accept(sock, (sockaddr *)&client_sockaddr, &sockaddr_len); - if (client_sock == -1) { - panicf("server: failed to accept connection %s", wsa_error()); + WSAPOLLFD pfds[256] = {}; + int pfd_count = 0; + { + pfds[pfd_count].fd = sock; + pfds[pfd_count].events = POLLIN; + pfd_count += 1; } - defer { wrapped_close_socket(client_sock); }; for (;;) { - char buff[1024]; - int bytes = recv(client_sock, buff, lengthof(buff) - 1, 0); - if (bytes == -1) { - panicf("server: failed recv %s", wsa_error()); + int timeout = -1; + int poll_count = WSAPoll(pfds, pfd_count, timeout); + if (poll_count == -1) { + panicf("server: failed to poll %s", wsa_error()); } - debugf("server: %.*s", bytes, buff); - if (bytes == 4 && buff[0] == 'q' && buff[1] == 'u' && buff[2] == 'i' && buff[3] == 't') { - break; + for (int i = 0; i < pfd_count; i += 1) { + bool ok = pfds[i].revents & (POLLIN | POLLHUP); + if (!ok) continue; + + // Handle new connection or receive data + if (pfds[i].fd == sock) { + sockaddr_storage addr = {}; + int sockaddr_len = sizeof(addr); + SOCKET client_sock = accept(sock, (sockaddr *)&addr, &sockaddr_len); + if (client_sock == -1) { + panicf("server: failed to accept connection %s", wsa_error()); + } + set_no_delay(client_sock); + pfds[i].fd = client_sock; + pfds[i].events = POLLIN; + pfds[i].revents = 0; + pfd_count += 1; + + debugf("server: new connection from: %s", serialize((sockaddr *)&addr)); + } else { + char buff[1024]; + int bytes = recv(pfds[i].fd, buff, lengthof(buff) - 1, 0); + if (bytes == -1) { + panicf("server: failed recv %s", wsa_error()); + } + debugf("server: %.*s", bytes, buff); + + if (bytes == 4 && buff[0] == 'q' && buff[1] == 'u' && buff[2] == 'i' && buff[3] == 't') { + break; + } + } } } + debugf("server: exiting"); } @@ -134,16 +184,20 @@ void run_client() { } defer { wrapped_close_socket(sock); }; + set_no_delay(sock); + for (;;) { const char *buff = "hello world!"; int buff_size = (int)strlen(buff); + debugf("client: sending %s", buff); int bytes = send(sock, buff, buff_size, 0); + debugf("bytes sent: %d", bytes); + // bytes can be less then buffer and that needs to be handled // that is the remaining amount needs to be sent? if (bytes == SOCKET_ERROR) { debugf("client: failed to send %s", wsa_error()); } - } } @@ -174,7 +228,7 @@ int main() { panicf("Version 2.2 of Winsock not available"); } - constexpr int thread_count = 2; + constexpr int thread_count = 8; HANDLE thread_handles[thread_count] = {}; DWORD thread_ids[thread_count] = {}; Thread_Context thread_datas[thread_count] = {};