technical-point-about-nanomsg-with-libuv

最近调研了如何使用libuv去监听nanomsgfd,以下是一些关键技术点

获取真实fd

nn_socket创建的返回值并不是真实系统的fd,而是nanomsg内部的数组序号。

NN_MAX_SOCKETS一般最大是512个,则这里返回的就是第几个数组序号。

需要用如下方式获取真实fd(以订阅为例),发布则将NN_RCVFD换成NN_SNDFD

1
2
3
4
int s = nn_socket(AF_SP, NN_SUB);
int fd;
size_t fd_len = sizeof(fd);
nn_getsockopt(s, NN_SOL_SOCKET, NN_RCVFD, &fd, &fd_len);

订阅同一端口的多个消息

假如发布端是一个进程,发布两种话题topic1topic2

1
2
3
4
5
6
int s = nn_socket(AF_SP, NN_PUB);
const char buf1[] = "topic1|data_here";
const char buf2[] = "topic2|data_here";
nn_send(s, buf1, strlen(buf1), 0);
sleep(1);
nn_send(s, buf2, strlen(buf2), 0);

订阅端是另一个进程,同时订阅topic1topic2

订阅端正确做法是创建一个nn_socket对象,然后调用nn_setsockopt两次去过滤两个话题,如下

正确做法

1
2
3
4
5
6
7
8
9
10
int s = nn_socket(AF_SP, NN_SUB);
nn_setsockopt(s, NN_SUB, NN_SUB_SUBSCRIBE, "topic1", 6);
nn_setsockopt(s, NN_SUB, NN_SUB_SUBSCRIBE, "topic2", 6);

# 这里根据上面的做法获取到订阅的真实fd

uv_poll_t poll_handle;
uv_poll_init(XXX, &poll_handle, fd);
uv_poll_start(&poll_handle, UV_READABLE, CallbackFunction);
uv_run(XXX);

正确做法里,topic1发布了,topic2还未发布,则回调触发时能正确收到topic1的数据

错误做法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int s1 = nn_socket(AF_SP, NN_SUB);
nn_setsockopt(s1, NN_SUB, NN_SUB_SUBSCRIBE, "topic1", 6);

int s2 = nn_socket(AF_SP, NN_SUB);
nn_setsockopt(s2, NN_SUB, NN_SUB_SUBSCRIBE, "topic2", 6);

# 这里根据上面的做法获取到订阅的真实fd1和fd2

uv_poll_t poll_handle_1;
uv_poll_init(XXX, &poll_handle_1, fd1);
uv_poll_start(&poll_handle_1, UV_READABLE, CallbackFunction1);

uv_poll_t poll_handle_2;
uv_poll_init(XXX, &poll_handle_2, fd2);
uv_poll_start(&poll_handle_2, UV_READABLE, CallbackFunction2);
uv_run(XXX);

在这个错误做法里,如果topic1发布了,topic2还没发布,则CallbackFunction1CallbackFunction2都会被调用

也就是任何一个话题发布,都会触发一遍所有回调

而正确做法里便不会出现问题