Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Multiple Clients with Select | Advanced Networking Techniques
Practice
Projects
Quizzes & Challenges
Visat
Challenges
/
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

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 3. Luku 1

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

bookMultiple Clients with Select

Pyyhkäise näyttääksesi valikon

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

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 3. Luku 1
some-alt