Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Blocking and Nonblocking IO | Building Network Applications
C Networking Basics

bookBlocking and Nonblocking IO

Note
Definition

Nonblocking mode offers an alternative. In this mode, socket operations return immediately, even if they would normally block. You can attempt to read or write, and if the operation cannot be completed right away, the function will return with an error (such as EWOULDBLOCK). This allows your program to continue doing other work, but you need a way to know when sockets are ready for reading or writing.

Understanding how your network program interacts with sockets is crucial for building efficient applications. By default, most socket operations in C are blocking. This means when you call functions like recv() or accept(), your program will pause and wait until the operation completes, such as when data arrives or a client connects. This approach is simple, but it can cause your application to become unresponsive if a socket takes a long time to respond.

blocking_nonblocking_select.c

blocking_nonblocking_select.c

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/select.h> #define PORT 9090 int main() { int listen_fd, client_fd, max_fd, activity; struct sockaddr_in server_addr, client_addr; socklen_t addrlen = sizeof(client_addr); char buffer[1024]; fd_set readfds; // Create socket listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Set to nonblocking int flags = fcntl(listen_fd, F_GETFL, 0); fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK); // Bind memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); close(listen_fd); exit(EXIT_FAILURE); } if (listen(listen_fd, 5) < 0) { perror("listen failed"); close(listen_fd); exit(EXIT_FAILURE); } printf("Listening on port %d...\n", PORT); while (1) { FD_ZERO(&readfds); FD_SET(listen_fd, &readfds); max_fd = listen_fd; // Wait for activity on the listening socket (no connected clients in this simple example) activity = select(max_fd + 1, &readfds, NULL, NULL, NULL); if (activity < 0 && errno != EINTR) { perror("select error"); } if (FD_ISSET(listen_fd, &readfds)) { client_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &addrlen); if (client_fd < 0) { if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("accept failed"); } } else { printf("New connection accepted.\n"); // Set client socket to nonblocking int cflags = fcntl(client_fd, F_GETFL, 0); fcntl(client_fd, F_SETFL, cflags | O_NONBLOCK); // Try to read data (will not block) ssize_t bytes = recv(client_fd, buffer, sizeof(buffer) - 1, 0); if (bytes > 0) { buffer[bytes] = '\0'; printf("Received: %s\n", buffer); } else if (bytes == 0) { printf("Client disconnected.\n"); } else { if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("recv failed"); } } close(client_fd); } } } close(listen_fd); return 0; }

This is where the select() function comes in. select() enables you to monitor multiple sockets at once, waiting until at least one is ready for some operation (like reading or writing). With select(), you can efficiently handle many connections within a single-threaded program, responding only when sockets are ready, and avoiding unnecessary blocking.

question mark

What does select() allow a network program to do?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 2. ChapterΒ 4

Ask AI

expand

Ask AI

ChatGPT

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

bookBlocking and Nonblocking IO

Swipe to show menu

Note
Definition

Nonblocking mode offers an alternative. In this mode, socket operations return immediately, even if they would normally block. You can attempt to read or write, and if the operation cannot be completed right away, the function will return with an error (such as EWOULDBLOCK). This allows your program to continue doing other work, but you need a way to know when sockets are ready for reading or writing.

Understanding how your network program interacts with sockets is crucial for building efficient applications. By default, most socket operations in C are blocking. This means when you call functions like recv() or accept(), your program will pause and wait until the operation completes, such as when data arrives or a client connects. This approach is simple, but it can cause your application to become unresponsive if a socket takes a long time to respond.

blocking_nonblocking_select.c

blocking_nonblocking_select.c

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/select.h> #define PORT 9090 int main() { int listen_fd, client_fd, max_fd, activity; struct sockaddr_in server_addr, client_addr; socklen_t addrlen = sizeof(client_addr); char buffer[1024]; fd_set readfds; // Create socket listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd < 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Set to nonblocking int flags = fcntl(listen_fd, F_GETFL, 0); fcntl(listen_fd, F_SETFL, flags | O_NONBLOCK); // Bind memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); close(listen_fd); exit(EXIT_FAILURE); } if (listen(listen_fd, 5) < 0) { perror("listen failed"); close(listen_fd); exit(EXIT_FAILURE); } printf("Listening on port %d...\n", PORT); while (1) { FD_ZERO(&readfds); FD_SET(listen_fd, &readfds); max_fd = listen_fd; // Wait for activity on the listening socket (no connected clients in this simple example) activity = select(max_fd + 1, &readfds, NULL, NULL, NULL); if (activity < 0 && errno != EINTR) { perror("select error"); } if (FD_ISSET(listen_fd, &readfds)) { client_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &addrlen); if (client_fd < 0) { if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("accept failed"); } } else { printf("New connection accepted.\n"); // Set client socket to nonblocking int cflags = fcntl(client_fd, F_GETFL, 0); fcntl(client_fd, F_SETFL, cflags | O_NONBLOCK); // Try to read data (will not block) ssize_t bytes = recv(client_fd, buffer, sizeof(buffer) - 1, 0); if (bytes > 0) { buffer[bytes] = '\0'; printf("Received: %s\n", buffer); } else if (bytes == 0) { printf("Client disconnected.\n"); } else { if (errno != EWOULDBLOCK && errno != EAGAIN) { perror("recv failed"); } } close(client_fd); } } } close(listen_fd); return 0; }

This is where the select() function comes in. select() enables you to monitor multiple sockets at once, waiting until at least one is ready for some operation (like reading or writing). With select(), you can efficiently handle many connections within a single-threaded program, responding only when sockets are ready, and avoiding unnecessary blocking.

question mark

What does select() allow a network program to do?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 2. ChapterΒ 4
some-alt