Multiple Clients with Select
Managing multiple clients efficiently is a common challenge in network programming. Using threads for each client can quickly become resource-intensive and complex. Instead, you can use the select() system call to monitor multiple file descriptors, such as sockets, for readiness to perform I/O operations. This allows a single-threaded server to handle multiple clients simultaneously. With select(), you can check which sockets are ready to read, write, or have errors, and then act on only those, avoiding the need to block on one client while others wait.
server_select.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/select.h> #define PORT 8080 #define MAX_CLIENTS FD_SETSIZE #define BUFFER_SIZE 1024 int main() { int listen_fd, new_fd, max_fd, activity, i, valread, sd; int client_socket[MAX_CLIENTS]; struct sockaddr_in address; char buffer[BUFFER_SIZE]; // Initialize all client_socket[] to 0 for (i = 0; i < MAX_CLIENTS; i++) client_socket[i] = 0; // Create listening socket if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Prepare address address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // Bind if (bind(listen_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // Listen if (listen(listen_fd, 5) < 0) { perror("listen"); exit(EXIT_FAILURE); } printf("Server listening on port %d\n", PORT); fd_set readfds; while (1) { // Clear and set file descriptors FD_ZERO(&readfds); FD_SET(listen_fd, &readfds); max_fd = listen_fd; // Add client sockets to set for (i = 0; i < MAX_CLIENTS; i++) { sd = client_socket[i]; if (sd > 0) FD_SET(sd, &readfds); if (sd > max_fd) max_fd = sd; } // Wait for activity activity = select(max_fd + 1, &readfds, NULL, NULL, NULL); if ((activity < 0) && (errno != EINTR)) { perror("select error"); } // Incoming connection if (FD_ISSET(listen_fd, &readfds)) { socklen_t addrlen = sizeof(address); if ((new_fd = accept(listen_fd, (struct sockaddr *)&address, &addrlen)) < 0) { perror("accept"); exit(EXIT_FAILURE); } printf("New connection: socket fd %d, IP: %s, port: %d\n", new_fd, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); // Add new socket to array for (i = 0; i < MAX_CLIENTS; i++) { if (client_socket[i] == 0) { client_socket[i] = new_fd; break; } } } // IO on client sockets for (i = 0; i < MAX_CLIENTS; i++) { sd = client_socket[i]; if (FD_ISSET(sd, &readfds)) { if ((valread = read(sd, buffer, BUFFER_SIZE)) == 0) { // Client disconnected getpeername(sd, (struct sockaddr *)&address, (socklen_t *)&addrlen); printf("Host disconnected: IP %s, port %d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); close(sd); client_socket[i] = 0; } else { buffer[valread] = '\0'; printf("Received from client %d: %s\n", sd, buffer); send(sd, buffer, valread, 0); // Echo back } } } } return 0; }
Danke für Ihr Feedback!
Fragen Sie AI
Fragen Sie AI
Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen
Großartig!
Completion Rate verbessert auf 8.33
Multiple Clients with Select
Swipe um das Menü anzuzeigen
Managing multiple clients efficiently is a common challenge in network programming. Using threads for each client can quickly become resource-intensive and complex. Instead, you can use the select() system call to monitor multiple file descriptors, such as sockets, for readiness to perform I/O operations. This allows a single-threaded server to handle multiple clients simultaneously. With select(), you can check which sockets are ready to read, write, or have errors, and then act on only those, avoiding the need to block on one client while others wait.
server_select.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/select.h> #define PORT 8080 #define MAX_CLIENTS FD_SETSIZE #define BUFFER_SIZE 1024 int main() { int listen_fd, new_fd, max_fd, activity, i, valread, sd; int client_socket[MAX_CLIENTS]; struct sockaddr_in address; char buffer[BUFFER_SIZE]; // Initialize all client_socket[] to 0 for (i = 0; i < MAX_CLIENTS; i++) client_socket[i] = 0; // Create listening socket if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Prepare address address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // Bind if (bind(listen_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // Listen if (listen(listen_fd, 5) < 0) { perror("listen"); exit(EXIT_FAILURE); } printf("Server listening on port %d\n", PORT); fd_set readfds; while (1) { // Clear and set file descriptors FD_ZERO(&readfds); FD_SET(listen_fd, &readfds); max_fd = listen_fd; // Add client sockets to set for (i = 0; i < MAX_CLIENTS; i++) { sd = client_socket[i]; if (sd > 0) FD_SET(sd, &readfds); if (sd > max_fd) max_fd = sd; } // Wait for activity activity = select(max_fd + 1, &readfds, NULL, NULL, NULL); if ((activity < 0) && (errno != EINTR)) { perror("select error"); } // Incoming connection if (FD_ISSET(listen_fd, &readfds)) { socklen_t addrlen = sizeof(address); if ((new_fd = accept(listen_fd, (struct sockaddr *)&address, &addrlen)) < 0) { perror("accept"); exit(EXIT_FAILURE); } printf("New connection: socket fd %d, IP: %s, port: %d\n", new_fd, inet_ntoa(address.sin_addr), ntohs(address.sin_port)); // Add new socket to array for (i = 0; i < MAX_CLIENTS; i++) { if (client_socket[i] == 0) { client_socket[i] = new_fd; break; } } } // IO on client sockets for (i = 0; i < MAX_CLIENTS; i++) { sd = client_socket[i]; if (FD_ISSET(sd, &readfds)) { if ((valread = read(sd, buffer, BUFFER_SIZE)) == 0) { // Client disconnected getpeername(sd, (struct sockaddr *)&address, (socklen_t *)&addrlen); printf("Host disconnected: IP %s, port %d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port)); close(sd); client_socket[i] = 0; } else { buffer[valread] = '\0'; printf("Received from client %d: %s\n", sd, buffer); send(sd, buffer, valread, 0); // Echo back } } } } return 0; }
Danke für Ihr Feedback!