TCP Server Example

The following example code demonstrates the implementation of a TCP server. The server sets up a listen server on a local port number, and waits for client connections. When a client connects, it forks a new child process to handle the client connection. This allows the server to continue running to service additional client connections. For each client connection, the server converts any message received to uppercase, and sends it back to the client.

 1#include <ctype.h>
 2#include <err.h>
 3#include <netdb.h>
 4#include <stdint.h>
 5#include <stdio.h>
 6#include <stdlib.h>
 7#include <string.h>
 8#include <sys/socket.h>
 9#include <sys/types.h>
10#include <unistd.h>
11
12#define BUF_SIZE 500
13
14int
15main(int argc, char *argv[])
16{
17
18  if (argc != 2) err(1, "Usage: %s port\n", argv[0]);
19  char const *portnum = argv[1];
20
21  struct addrinfo hints = {
22      .ai_family = AF_UNSPEC,     /* IPv4 or IPv6 */
23      .ai_socktype = SOCK_STREAM, /* Stream Socket */
24      .ai_flags = AI_PASSIVE,     /* Listen socket */
25  };
26
27  struct addrinfo *result, *rp;
28  int s;
29  s = getaddrinfo(NULL, portnum, &hints, &result);
30  if (s != 0) errx(1, "getaddrinfo: %s\n", gai_strerror(s));
31
32  /* getaddrinfo() returns a list of address structures.
33     Try each address until we successfully bind(2).
34     If socket(2) (or bind(2)) fails, we (close the socket
35     and) try the next address. */
36  int listen_fd;
37  for (rp = result; rp != NULL; rp = rp->ai_next) {
38    listen_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
39    if (listen_fd == -1) continue;
40    if (bind(listen_fd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Success */
41    close(listen_fd);
42  }
43  freeaddrinfo(result); /* No longer needed */
44  if (rp == NULL) err(1, "could not bind socket");
45
46  /* Set up listen queue for clients */
47  if (listen(listen_fd, 10) < 0) err(1, "listen");
48
49  /* Handle incoming client connections */
50  for (;;) {
51    struct sockaddr_storage peer_addr;
52    socklen_t peer_addrlen = sizeof peer_addr;
53    int client_fd = accept(listen_fd, (void *)&peer_addr, &peer_addrlen);
54    if (client_fd < 0) err(1, "accept");
55
56    char host[NI_MAXHOST], serv[NI_MAXSERV];
57    s = getnameinfo((void *)&peer_addr,
58                    peer_addrlen,
59                    host,
60                    sizeof host,
61                    serv,
62                    sizeof serv,
63                    NI_NUMERICSERV);
64    if (s == 0) {
65      printf("Incoming connection from %s on port %s\n", host, serv);
66    } else {
67      if (s == EAI_SYSTEM) err(1, "getaddrinfo");
68      else errx(1, "getaddrinfo: %s", gai_strerror(s));
69    }
70
71    switch (fork()) {
72      case 0:
73        close(listen_fd);
74        /* Send and receive data */
75        for (;;) {
76          char buf[BUFSIZ];
77          size_t n_in = read(client_fd, buf, sizeof buf);
78          if (n_in < 0) err(1, "read");
79          if (n_in == 0) break;
80          for (size_t i = 0; i < n_in; ++i) buf[i] = toupper(buf[i]);
81          for (size_t n_out = 0; n_out < n_in;) {
82            size_t n = write(client_fd, buf + n_out, n_in - n_out);
83            if (n < 0) err(1, "write");
84            n_out += n;
85          }
86        }
87        close(client_fd);
88        exit(0);
89      case -1:
90        err(1, "fork");
91      default:
92        close(client_fd);
93    }
94  }
95}