Graceful Shutdown
When working with network programs in C, it is essential to handle the shutdown process carefully to avoid resource leaks and undefined behavior. Properly closing sockets and cleaning up resources ensures that your application does not leave open file descriptors, which could eventually exhaust system resources and prevent new connections from being established. When a socket is no longer needed, you must signal the end of communication, gracefully close the connection, and release any resources associated with it. This involves using the shutdown() function to indicate that you have finished sending or receiving data, followed by the close() function to free the socket descriptor.
graceful_shutdown.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 8080 void run_server() { int server_fd, client_fd; struct sockaddr_in address; socklen_t addrlen = sizeof(address); char buffer[1024] = {0}; server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("Server socket failed"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); close(server_fd); exit(EXIT_FAILURE); } if (listen(server_fd, 1) < 0) { perror("Listen failed"); close(server_fd); exit(EXIT_FAILURE); } printf("Server listening on port %d...\n", PORT); client_fd = accept(server_fd, (struct sockaddr *)&address, &addrlen); if (client_fd < 0) { perror("Accept failed"); close(server_fd); exit(EXIT_FAILURE); } int valread = read(client_fd, buffer, sizeof(buffer)); printf("Server received: %s\n", buffer); // Graceful shutdown: stop further sends and receives shutdown(client_fd, SHUT_RDWR); close(client_fd); close(server_fd); printf("Server sockets closed gracefully.\n"); } void run_client() { int sock; struct sockaddr_in serv_addr; char *message = "Hello, server!"; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("Client socket failed"); exit(EXIT_FAILURE); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { perror("Invalid address"); close(sock); exit(EXIT_FAILURE); } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("Connection failed"); close(sock); exit(EXIT_FAILURE); } send(sock, message, strlen(message), 0); // Graceful shutdown: stop further sends and receives shutdown(sock, SHUT_RDWR); close(sock); printf("Client socket closed gracefully.\n"); } int main(int argc, char const *argv[]) { if (argc != 2) { printf("Usage: %s [server|client]\n", argv[0]); return 1; } if (strcmp(argv[1], "server") == 0) { run_server(); } else if (strcmp(argv[1], "client") == 0) { run_client(); } else { printf("Unknown role: %s\n", argv[1]); return 1; } return 0; }
This program shows a simple TCP clientβserver interaction in C. The server creates a socket, binds to port 8080, listens for a connection, accepts a client, reads the message, and then shuts down cleanly. The client creates a socket, connects to 127.0.0.1:8080, sends a short message, and closes the connection. Together, they demonstrate the basic TCP workflow: socket creation, connection, data transfer, and graceful shutdown.
This example handles only one client and does not echo the message back to the client. In a real TCP echo server, the server would send the received data back before closing the connection.
Thanks for your feedback!
Ask AI
Ask AI
Ask anything or try one of the suggested questions to begin our chat
Can you explain the difference between shutdown() and close() in socket programming?
What happens if I don't properly close sockets in my C network program?
Can you provide an example of how to use shutdown() and close() in a C program?
Awesome!
Completion rate improved to 8.33
Graceful Shutdown
Swipe to show menu
When working with network programs in C, it is essential to handle the shutdown process carefully to avoid resource leaks and undefined behavior. Properly closing sockets and cleaning up resources ensures that your application does not leave open file descriptors, which could eventually exhaust system resources and prevent new connections from being established. When a socket is no longer needed, you must signal the end of communication, gracefully close the connection, and release any resources associated with it. This involves using the shutdown() function to indicate that you have finished sending or receiving data, followed by the close() function to free the socket descriptor.
graceful_shutdown.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 8080 void run_server() { int server_fd, client_fd; struct sockaddr_in address; socklen_t addrlen = sizeof(address); char buffer[1024] = {0}; server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("Server socket failed"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("Bind failed"); close(server_fd); exit(EXIT_FAILURE); } if (listen(server_fd, 1) < 0) { perror("Listen failed"); close(server_fd); exit(EXIT_FAILURE); } printf("Server listening on port %d...\n", PORT); client_fd = accept(server_fd, (struct sockaddr *)&address, &addrlen); if (client_fd < 0) { perror("Accept failed"); close(server_fd); exit(EXIT_FAILURE); } int valread = read(client_fd, buffer, sizeof(buffer)); printf("Server received: %s\n", buffer); // Graceful shutdown: stop further sends and receives shutdown(client_fd, SHUT_RDWR); close(client_fd); close(server_fd); printf("Server sockets closed gracefully.\n"); } void run_client() { int sock; struct sockaddr_in serv_addr; char *message = "Hello, server!"; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("Client socket failed"); exit(EXIT_FAILURE); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { perror("Invalid address"); close(sock); exit(EXIT_FAILURE); } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("Connection failed"); close(sock); exit(EXIT_FAILURE); } send(sock, message, strlen(message), 0); // Graceful shutdown: stop further sends and receives shutdown(sock, SHUT_RDWR); close(sock); printf("Client socket closed gracefully.\n"); } int main(int argc, char const *argv[]) { if (argc != 2) { printf("Usage: %s [server|client]\n", argv[0]); return 1; } if (strcmp(argv[1], "server") == 0) { run_server(); } else if (strcmp(argv[1], "client") == 0) { run_client(); } else { printf("Unknown role: %s\n", argv[1]); return 1; } return 0; }
This program shows a simple TCP clientβserver interaction in C. The server creates a socket, binds to port 8080, listens for a connection, accepts a client, reads the message, and then shuts down cleanly. The client creates a socket, connects to 127.0.0.1:8080, sends a short message, and closes the connection. Together, they demonstrate the basic TCP workflow: socket creation, connection, data transfer, and graceful shutdown.
This example handles only one client and does not echo the message back to the client. In a real TCP echo server, the server would send the received data back before closing the connection.
Thanks for your feedback!