1+ #include < stdint.h>
2+ #include < stdlib.h>
3+ #include < string.h>
4+ #include < stdio.h>
5+ #include < errno.h>
6+ #include < unistd.h>
7+ #include < arpa/inet.h>
8+ #include < sys/socket.h>
9+ #include < netinet/ip.h>
10+ #include < cassert>
11+
12+
13+ static void msg (const char *msg) {
14+ fprintf (stderr, " %s\n " , msg);
15+ }
16+
17+ static void die (const char *msg) {
18+ int err = errno;
19+ fprintf (stderr, " [%d] %s\n " , err, msg);
20+ abort ();
21+ }
22+
23+ const size_t k_max_msg = 4096 ;
24+
25+ // Function ensures that the full amount of data is read before proceeding.
26+ // Read a specified number of bytes('n') from a file descriptor ('fd') into buffer('buf').
27+ static int32_t read_full (int fd, char *buf, size_t n){
28+ while (n > 0 ) {
29+ ssize_t rv = read (fd, buf, n);
30+ if (rv <= 0 ) {
31+ return -1 ; // Error, or unexpected EOF
32+ }
33+ assert (static_cast <size_t >(rv) <= n); // Check the number of bytes read doesnt exceed the number of bytes requested
34+ n -= static_cast <size_t >(rv);
35+ buf += rv;
36+ }
37+
38+ return 0 ;
39+ }
40+
41+ static int32_t write_all (int fd, const char *buf, size_t n) {
42+ while (n > 0 ) {
43+ ssize_t rv = write (fd, buf, n);
44+ if (rv <= 0 ) {
45+ return -1 ; // Error
46+ }
47+ assert (static_cast <size_t >(rv) <= n);
48+ n -= static_cast <size_t >(rv);
49+ buf += rv;
50+ }
51+
52+ return 0 ;
53+ }
54+
55+ static int32_t one_request (int connfd) {
56+ // 4 bytes header
57+ char rbuf[4 + k_max_msg + 1 ];
58+ errno = 0 ;
59+ int32_t err = read_full (connfd, rbuf, 4 );
60+ if (err) {
61+ if (errno == 0 ) {
62+ msg (" EOF" );
63+ } else {
64+ msg (" read() error" );
65+ }
66+ return err;
67+ }
68+
69+ uint32_t len = 0 ;
70+ memcpy (&len, rbuf, 4 ); // assume little endian
71+ if (len > k_max_msg) {
72+ msg (" too long" );
73+ return -1 ;
74+ }
75+
76+ // request body
77+ err = read_full (connfd, &rbuf[4 ], len);
78+ if (err) {
79+ msg (" read() error" );
80+ return err;
81+ }
82+
83+ // do something
84+ rbuf[4 + len] = ' \0 ' ;
85+ printf (" client says: %s\n " , &rbuf[4 ]);
86+
87+ // replay using the same protocol
88+ const char replay[] = " world" ;
89+ char wbuf[4 + sizeof (replay)];
90+ len = static_cast <uint32_t >(strlen (replay));
91+ memcpy (wbuf, &len, 4 );
92+ memcpy (&wbuf[4 ], replay, len);
93+
94+ return write_all (connfd, wbuf, 4 + len);
95+
96+ }
97+
98+ int main () {
99+ int fd = socket (AF_INET, SOCK_STREAM, 0 );
100+ if (fd < 0 ) {
101+ die (" socket()" );
102+ }
103+
104+ // this is needed for most server applications
105+ int val = 1 ;
106+ setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val));
107+
108+ // bind
109+ struct sockaddr_in addr = {};
110+ addr.sin_family = AF_INET;
111+ addr.sin_port = ntohs (1234 );
112+ addr.sin_addr .s_addr = ntohl (0 ); // wildcard address 0.0.0.0
113+ int rv = bind (fd, (const sockaddr *)&addr, sizeof (addr));
114+ if (rv) {
115+ die (" bind()" );
116+ }
117+
118+ // listen
119+ rv = listen (fd, SOMAXCONN);
120+ if (rv) {
121+ die (" listen()" );
122+ }
123+
124+ while (true ) {
125+ // accept
126+ struct sockaddr_in client_addr = {};
127+ socklen_t socklen = sizeof (client_addr);
128+ int connfd = accept (fd, (struct sockaddr *)&client_addr, &socklen);
129+ if (connfd < 0 ) {
130+ continue ; // error
131+ }
132+
133+ // only serves one client connection at once
134+ while (true ) {
135+ int32_t err = one_request (connfd);
136+ if (err) {
137+ break ;
138+ }
139+ }
140+ close (connfd);
141+ }
142+
143+ return 0 ;
144+ }
0 commit comments