Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen Multiple Clients with Select | Advanced Networking Techniques
C Networking Basics

bookMultiple 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

server_select.c

copy
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; }
question mark

Why is select() useful for handling multiple clients in a server?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 3. Kapitel 1

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

bookMultiple 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

server_select.c

copy
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; }
question mark

Why is select() useful for handling multiple clients in a server?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 3. Kapitel 1
some-alt