/* hello_server.c Adapted from Douglas Comer's "Internetworking with TCP/IP" by Jeff Ondich and Lauren Jantz, summer 1995. Rewritten in C++, Jeff Ondich, January 2000. Re-rewritten in C, Jeff Ondich, March 2023. This program is an iterative server for a tiny "hello world" sort of protocol. Once a TCP connection request arrives, this server accepts the connection, sends a message string (with no null-termination) to the client, and then closes the connection. See hello_client.c for more details. */ #include #include #include #include #include #include #include "tcp_utilities.h" // Prototypes of functions in this file. void process_request(int socket_descriptor, const char *message); void log_connection(int socket_descriptor, const char *server_name); int main(int argc, char *argv[]) { // Parse the command line. const char *server_name = argv[0]; if (argc != 3) { fprintf(stderr, "Usage: %s port message\n", server_name); fprintf(stderr, "For example: %s 5000 \"Hi there, client!\"\n", server_name); return 1; } int port; if (sscanf(argv[1], "%d", &port) != 1) { fprintf(stderr, "port \"%s\" is not a decimal integer\n", argv[1]); return 1; } const char *message = argv[2]; // Start listening at the specified port. int main_socket = prepare_to_accept_connections(port); fprintf(stderr, "%s is ready to serve at port %d.\n", argv[0], port); // Accept and process connections until the world ends. while (1) { // Answer the phone. note that accept() makes a duplicate of // the original socket so that, if you wished, you could have // the server listen for more connection requests while at the // same time processing the current request. See // hello_server_concurrent.c for details. struct sockaddr_in peer_address; socklen_t address_length = sizeof(peer_address); int new_socket = accept(main_socket, (struct sockaddr *)&peer_address, &address_length); if (new_socket < 0) { fprintf(stderr, "%s: accept failed: %s\n", argv[0], strerror(errno)); exit(1); } // Process the request. log_connection(new_socket, server_name); process_request(new_socket, message); // Close the connection. close(new_socket); } return 0; } // Report information about the current connection request. // This could, of course, be more sophisticated than printing a // message to standard error, but it's not. void log_connection(int socket_descriptor, const char *server_name) { const int buffer_size = 100; char peer_name[buffer_size]; get_peer_host_name(socket_descriptor, peer_name, buffer_size); fprintf(stderr, "%s: processed request from %s\n", server_name, peer_name); } // Implements this server's protocol. Since this server's protocol is pretty // darned trivial, there's not much here. void process_request(int socket_descriptor, const char *message) { // Send the message. Note that writing to a socket is simpler than // reading from one, since you can write everything at once, while reading // depends on when the pieces of the incoming message arrive via the network. if (write(socket_descriptor, message, strlen(message)) < 0) { fprintf(stderr, "An error occurred while writing the message: %s\n", strerror(errno)); } }