Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c834ff5

Browse files
committed
Implement basic TCP sever funcionality
1 parent 37f2990 commit c834ff5

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

server.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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

Comments
 (0)