Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn 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

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 3. ChapterΒ 1

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

Suggested prompts:

Can you explain how the select() system call works in more detail?

Can you provide a simple example of using select() in a server?

What are the limitations of using select() for handling multiple clients?

bookMultiple Clients with Select

Swipe to show menu

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

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 3. ChapterΒ 1
some-alt