wangzhengquan
2020-12-04 aa2f3b2a9968bb4928463bdae05fb026d16b60bb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# <center>BHomeBus 使用指南</center>
    
    
## 1. BHomeBus包含的角色
- NetProxyService(网络代理服务): 负责跨机器转发发布或请求消息
- BusService( 总线服务): 发布订阅的路由,负责记录订阅者的消息并把发布者发布的消息转发给感兴趣的订阅者。
- Pub/Sub Client(发布订阅客户端): 向BusService发布消息或者在BusService上订阅感兴趣的消息
- Request/Reply Client (请求应答客户端):向其他机器/进程发送请求消息或者从其他机器/进程接受应答消息
 
其中BusService和NetProxyService是服务进程,使用者把它起来后就不需要关心了。使用者主要关注的是Pub/Sub Client 和 Request/Reply Client
 
## 2. 使用说明
具体每个方法的及其参数的说明可以参看它们对应的头文件。
 
使用时,每台主机都需要先把BusService和NetProxyService这两个服务启动起来。因为后面的功能都依赖这两个服务。
 
### 2.1 启动NetProxyService
NetProxyService的头文件是 net_mod_server_socket_wrapper.h. 下面的代码启动端口是5000的网络代理服务
 
```
void *serverSocket  = net_mod_server_socket_open(5000);
if(net_mod_server_socket_start(serverSocket) != 0) {
    err_exit(errno, "net_mod_server_socket_start");
}
```
 
### 2.2 启动BusService
BusService, Pub/Sub Client 和 Request/Reply Client的头文件都是 net_mod_socket_wrapper.h, 下面启动key是8的Bus服务.
 
```
 
void * server_socket = net_mod_socket_open();
 
net_mod_socket_bind(server_socket, 8);
 
net_mod_socket_start_bus(server_socket);
 
```
 
###  2.3 Request/Reply 用例说明
现在模拟一个场景,A向B和C发送一个请求,B和C收到请求后分别返回一个响应给A 。假设A的IP是192.168.20.101,B的IP是192.168.20.102, C的IP是192.168.20.103, 它们的key都是100, 代理server的端口是5000。
 
A 的代码如下:
 
```
int recv_arr_size, n;
net_mod_recv_msg_t *recv_arr;
const char* content = "HELLO WORLD!":
net_mod_socket_bind(client, 100);
net_node_t node_arr = {
    {"192.168.20.102", 5000, 100},
    {"192.168.20.103", 5000, 100}
};
int node_arr_size = 2;
 
void *client = net_mod_socket_open();
n = net_mod_socket_sendandrecv(client, node_arr, node_arr_size, content, strlen(content), &recv_arr, &recv_arr_size);
printf(">>> %d nodes reply\n", n);
for(i=0; i<recv_arr_size; i++) {
    printf("host:%s, port: %d, key:%d, content: %s\n", 
        recv_arr[i].host,
        recv_arr[i].port,
        recv_arr[i].key,
        recv_arr[i].content
    );
}
 
// 使用完后,不要忘记释放掉
net_mod_socket_free_recv_msg_arr(recv_arr, recv_arr_size);
 
```
 
B 和 C的代码如下:
 
```
void *client = net_mod_socket_open();
net_mod_socket_bind(client, 100);
int size;
void *recvbuf;
char sendbuf[512];
int rv;
int remote_port;
while ( (rv = net_mod_socket_recvfrom(client, &recvbuf, &size, &remote_port) ) == 0) {
    // printf( "server: RECEIVED REQUEST FROM PORT %d NAME %s\n", remote_port, recvbuf);
    sprintf(sendbuf, "RECEIVED  PORT %d NAME %s", remote_port, recvbuf);
    net_mod_socket_sendto(client, sendbuf, strlen(sendbuf) + 1, remote_port);
    free(recvbuf);
}
```
 
 
### 2.3 Pub/Sub 用例说明
 
现在模拟一个场景,B 和 C订阅了主题news, A 发布了该主题相关的内容 。假设A的IP是192.168.20.101,B的IP是192.168.20.102, C的IP是192.168.20.103, 它们的key都是200, Bus的key是8, 代理server的端口是5000.
 
A的代码如下:
 
```
int n;
const char* topic = "news":
const char* content = "HELLO WORLD!":
void *client = net_mod_socket_open();
net_mod_socket_bind(client, 200);
net_node_t node_arr = {
    {"192.168.20.102", 5000, 8},
    {"192.168.20.103", 5000, 8}
};
int node_arr_size = 2;
 
void *client = net_mod_socket_open();
net_mod_socket_bind(client, 200);
n = net_mod_socket_pub(client, pub_node_arr, pub_node_arr_size, topic, strlen(topic)+1, content, strlen(content)+1);
printf("pub %d nodes\n", n);
```
 
B 和 C 的代码如下
```
const char* topic = "news":
 
void *client = net_mod_socket_open();
net_mod_socket_bind(client, 200);
while (net_mod_socket_sub(client, topic, strlen(topic),  8) == 0) {
 printf("%d Sub success!\n", net_mod_socket_get_key(client));
}
```
 
更具体的实例代码请参看`test_net_mod_socket.c`
 
## 3 设计说明
 
使用的时候,大家会对BusService和NetProxyService这两个需要额外启动服务感到疑惑。下面重点队这两个服务做做一些说明。
 
### 3.1 Bus设计
 
 
![Bus示意图](./bus_service.png)
 
上面这张示意图是说订阅news的Client有A和B,订阅sports的有B和C,这些都在总线里记录着。当A向总线pub和主题sports相关的内容时,B和C会通过总线收到这个主题的消息。
 
### 3.2 NetProxyService设计
 
 
![NetProxyService示意图](./network_req_rep.png)
 
上面这张图跨机器请求应答的示意图。这张示意图时说当节点A向节点B的key 1001队列和key 1002队列发送消息时,它会首先发送到节点B的网络代理server上。网络代理server会把请求消息转发到相应的队列上,并接受应答返回给节点A。
 
同理跨机器的发布订阅也是通过这样的方式交互的。