Skip to content

Commit e129e88

Browse files
author
241200050
committed
feat(redis): 添加 Redis 协议相关的客户端和服务器示例代码- 新增多个 Redis 协议实现的客户端和服务器代码示例
- 演示了如何使用 socket 进行网络通信- 实现了基本的请求响应模型和数据传输 - 优化了错误处理和资源管理
1 parent 35e57fa commit e129e88

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+9521
-0
lines changed

C++/C++常见知识点.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct _Vector_impl
9494

9595
==== 虚函数实现
9696
C++多态分为静态多态(编译时多态)和动态多态(运行时多态)两大类,静态多态通过重载,模板来实现;动态多态是通过虚函数实现。
97+
9798
虚函数通过虚函数表vtbl(virtual table)和虚函数表指针vptr(virtual table pointer)来实现动态多态。当调用一个虚函数时,被执行的代码和调用函数的对象的动态类型相一致,当一个类声明了虚函数或者继承了虚函数,这个类就会有自己的vtbl,vtbl实际上就是一个函数指针数组,有的编译器用的是链表,不过方法都差不多。vtbl中每一个元素都对应一个函数指针,函数指针指向该类的一个虚函数,实际上每一个对象都会包含一个vptr,vptr指向该类的vtbl;
9899

99100
|===

src/redis/03/03_client.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
11+
12+
static void die(const char *msg) {
13+
int err = errno;
14+
fprintf(stderr, "[%d] %s\n", err, msg);
15+
abort();
16+
}
17+
18+
int main() {
19+
int fd = socket(AF_INET, SOCK_STREAM, 0);
20+
if (fd < 0) {
21+
die("socket()");
22+
}
23+
24+
struct sockaddr_in addr = {};
25+
addr.sin_family = AF_INET;
26+
addr.sin_port = ntohs(1234);
27+
addr.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); // 127.0.0.1
28+
int rv = connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
29+
if (rv) {
30+
die("connect");
31+
}
32+
33+
char msg[] = "hello";
34+
write(fd, msg, strlen(msg));
35+
36+
char rbuf[64] = {};
37+
ssize_t n = read(fd, rbuf, sizeof(rbuf) - 1);
38+
if (n < 0) {
39+
die("read");
40+
}
41+
printf("server says: %s\n", rbuf);
42+
close(fd);
43+
return 0;
44+
}

src/redis/03/03_server.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
11+
12+
static void msg(const char *msg) {
13+
fprintf(stderr, "%s\n", msg);
14+
}
15+
16+
static void die(const char *msg) {
17+
int err = errno;
18+
fprintf(stderr, "[%d] %s\n", err, msg);
19+
abort();
20+
}
21+
22+
static void do_something(int connfd) {
23+
char rbuf[64] = {};
24+
ssize_t n = read(connfd, rbuf, sizeof(rbuf) - 1);
25+
if (n < 0) {
26+
msg("read() error");
27+
return;
28+
}
29+
fprintf(stderr, "client says: %s\n", rbuf);
30+
31+
char wbuf[] = "world";
32+
write(connfd, wbuf, strlen(wbuf));
33+
}
34+
35+
int main() {
36+
int fd = socket(AF_INET, SOCK_STREAM, 0);
37+
if (fd < 0) {
38+
die("socket()");
39+
}
40+
41+
// this is needed for most server applications
42+
int val = 1;
43+
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
44+
45+
// bind
46+
struct sockaddr_in addr = {};
47+
addr.sin_family = AF_INET;
48+
addr.sin_port = ntohs(1234);
49+
addr.sin_addr.s_addr = ntohl(0); // wildcard address 0.0.0.0
50+
int rv = bind(fd, (const struct sockaddr *)&addr, sizeof(addr));
51+
if (rv) {
52+
die("bind()");
53+
}
54+
55+
// listen
56+
rv = listen(fd, SOMAXCONN);
57+
if (rv) {
58+
die("listen()");
59+
}
60+
61+
while (true) {
62+
// accept
63+
struct sockaddr_in client_addr = {};
64+
socklen_t addrlen = sizeof(client_addr);
65+
int connfd = accept(fd, (struct sockaddr *)&client_addr, &addrlen);
66+
if (connfd < 0) {
67+
continue; // error
68+
}
69+
70+
do_something(connfd);
71+
close(connfd);
72+
}
73+
74+
return 0;
75+
}

src/redis/04/04_client.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include <stdio.h>
6+
#include <errno.h>
7+
#include <unistd.h>
8+
#include <arpa/inet.h>
9+
#include <sys/socket.h>
10+
#include <netinet/ip.h>
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+
static int32_t read_full(int fd, char *buf, size_t n) {
24+
while (n > 0) {
25+
ssize_t rv = read(fd, buf, n);
26+
if (rv <= 0) {
27+
return -1; // error, or unexpected EOF
28+
}
29+
assert((size_t)rv <= n);
30+
n -= (size_t)rv;
31+
buf += rv;
32+
}
33+
return 0;
34+
}
35+
36+
static int32_t write_all(int fd, const char *buf, size_t n) {
37+
while (n > 0) {
38+
ssize_t rv = write(fd, buf, n);
39+
if (rv <= 0) {
40+
return -1; // error
41+
}
42+
assert((size_t)rv <= n);
43+
n -= (size_t)rv;
44+
buf += rv;
45+
}
46+
return 0;
47+
}
48+
49+
const size_t k_max_msg = 4096;
50+
51+
static int32_t query(int fd, const char *text) {
52+
uint32_t len = (uint32_t)strlen(text);
53+
if (len > k_max_msg) {
54+
return -1;
55+
}
56+
57+
char wbuf[4 + k_max_msg];
58+
memcpy(wbuf, &len, 4); // assume little endian
59+
memcpy(&wbuf[4], text, len);
60+
if (int32_t err = write_all(fd, wbuf, 4 + len)) {
61+
return err;
62+
}
63+
64+
// 4 bytes header
65+
char rbuf[4 + k_max_msg + 1];
66+
errno = 0;
67+
int32_t err = read_full(fd, rbuf, 4);
68+
if (err) {
69+
msg(errno == 0 ? "EOF" : "read() error");
70+
return err;
71+
}
72+
73+
memcpy(&len, rbuf, 4); // assume little endian
74+
if (len > k_max_msg) {
75+
msg("too long");
76+
return -1;
77+
}
78+
79+
// reply body
80+
err = read_full(fd, &rbuf[4], len);
81+
if (err) {
82+
msg("read() error");
83+
return err;
84+
}
85+
86+
// do something
87+
printf("server says: %.*s\n", len, &rbuf[4]);
88+
return 0;
89+
}
90+
91+
int main() {
92+
int fd = socket(AF_INET, SOCK_STREAM, 0);
93+
if (fd < 0) {
94+
die("socket()");
95+
}
96+
97+
struct sockaddr_in addr = {};
98+
addr.sin_family = AF_INET;
99+
addr.sin_port = ntohs(1234);
100+
addr.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); // 127.0.0.1
101+
int rv = connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
102+
if (rv) {
103+
die("connect");
104+
}
105+
106+
// multiple requests
107+
int32_t err = query(fd, "hello1");
108+
if (err) {
109+
goto L_DONE;
110+
}
111+
err = query(fd, "hello2");
112+
if (err) {
113+
goto L_DONE;
114+
}
115+
err = query(fd, "hello3");
116+
if (err) {
117+
goto L_DONE;
118+
}
119+
120+
L_DONE:
121+
close(fd);
122+
return 0;
123+
}

src/redis/04/04_server.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include <stdio.h>
6+
#include <errno.h>
7+
#include <unistd.h>
8+
#include <arpa/inet.h>
9+
#include <sys/socket.h>
10+
#include <netinet/ip.h>
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+
static int32_t read_full(int fd, char *buf, size_t n) {
26+
while (n > 0) {
27+
ssize_t rv = read(fd, buf, n);
28+
if (rv <= 0) {
29+
return -1; // error, or unexpected EOF
30+
}
31+
assert((size_t)rv <= n);
32+
n -= (size_t)rv;
33+
buf += rv;
34+
}
35+
return 0;
36+
}
37+
38+
static int32_t write_all(int fd, const char *buf, size_t n) {
39+
while (n > 0) {
40+
ssize_t rv = write(fd, buf, n);
41+
if (rv <= 0) {
42+
return -1; // error
43+
}
44+
assert((size_t)rv <= n);
45+
n -= (size_t)rv;
46+
buf += rv;
47+
}
48+
return 0;
49+
}
50+
51+
static int32_t one_request(int connfd) {
52+
// 4 bytes header
53+
char rbuf[4 + k_max_msg];
54+
errno = 0;
55+
int32_t err = read_full(connfd, rbuf, 4);
56+
if (err) {
57+
msg(errno == 0 ? "EOF" : "read() error");
58+
return err;
59+
}
60+
61+
uint32_t len = 0;
62+
memcpy(&len, rbuf, 4); // assume little endian
63+
if (len > k_max_msg) {
64+
msg("too long");
65+
return -1;
66+
}
67+
68+
// request body
69+
err = read_full(connfd, &rbuf[4], len);
70+
if (err) {
71+
msg("read() error");
72+
return err;
73+
}
74+
75+
// do something
76+
fprintf(stderr, "client says: %.*s\n", len, &rbuf[4]);
77+
78+
// reply using the same protocol
79+
const char reply[] = "world";
80+
char wbuf[4 + sizeof(reply)];
81+
len = (uint32_t)strlen(reply);
82+
memcpy(wbuf, &len, 4);
83+
memcpy(&wbuf[4], reply, len);
84+
return write_all(connfd, wbuf, 4 + len);
85+
}
86+
87+
int main() {
88+
int fd = socket(AF_INET, SOCK_STREAM, 0);
89+
if (fd < 0) {
90+
die("socket()");
91+
}
92+
93+
// this is needed for most server applications
94+
int val = 1;
95+
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
96+
97+
// bind
98+
struct sockaddr_in addr = {};
99+
addr.sin_family = AF_INET;
100+
addr.sin_port = ntohs(1234);
101+
addr.sin_addr.s_addr = ntohl(0); // wildcard address 0.0.0.0
102+
int rv = bind(fd, (const sockaddr *)&addr, sizeof(addr));
103+
if (rv) {
104+
die("bind()");
105+
}
106+
107+
// listen
108+
rv = listen(fd, SOMAXCONN);
109+
if (rv) {
110+
die("listen()");
111+
}
112+
113+
while (true) {
114+
// accept
115+
struct sockaddr_in client_addr = {};
116+
socklen_t addrlen = sizeof(client_addr);
117+
int connfd = accept(fd, (struct sockaddr *)&client_addr, &addrlen);
118+
if (connfd < 0) {
119+
continue; // error
120+
}
121+
122+
while (true) {
123+
// here the server only serves one client connection at once
124+
int32_t err = one_request(connfd);
125+
if (err) {
126+
break;
127+
}
128+
}
129+
close(connfd);
130+
}
131+
132+
return 0;
133+
}

0 commit comments

Comments
 (0)