这里分别分析server端和client端的过程。使用的协议为xpub/xsub,底层协议为IPC。
1. server端 (xpub)
1.1 nn_socket()
nn_socket()创建一个nn_sock表示nanomsg socket,domain和protocol指定了协议类型。
int nn_socket (int domain, int protocol);
nn_sock的成员sockbase指向协议对象,也就是nn_sockbase派生类的实例,这里是nn_xpub。nn_xpub用自身指定sockbase的值,还用自己的虚函数nn_xpub_sockbase_vfptr设置nn_sockbase的虚函数表vfptr。
nn_xpub与底层传输协议对象间需要一个数据通道,它的成员outpipes就是保存该通道的。当连接准备好时,底层对象会调用nn_sockbase_vfptr->add()通知nn_xpub。(对nn_xpub来说,add()是nn_xpub_add())
nn_socket()首先在nn_global的nn_sock[]中找到空闲位置,然后调用nn_global_create_socket()创建nn_sock对象。
- nn_sock_init()初始化nn_sock对象。因为nn_sock是顶层对象,所以用nn_fsm_init_root()初始化。
- nn_efd_init()初始化文件描述符sndefd和rcvfd分别用于发送和接收。
- 在全局数组nn_socktypes[]中保存了所有协议对象的创建信息nn_socktype。nn_sock_init()根据调用者指定的domain和protocol,在其中查找对应的nn_socktype,然后调用nn_socktype->create()。这里找到的是nn_xpub_socktype,调用nn_xpub_create()。
- 在nn_xpub_create()中,nn_xpub用自己的虚函数nn_xpub_sockbase_vfptr初始化nn_sockbase的虚函数表。
1.2 nn_bind()
nn_bind()根据指定的底层传输协议,初始化一系列底层对象,并把它们绑定到指定的地址上去。
int nn_bind (int s, const char *addr);
addr参数包括了协议类型和地址,如“ipc:///tmp/pubsub.ipc”,“ipc”是传输协议类型,“///tmp/pubsub.ipc”是地址。
这个过程中创建的对象包括:
- nn_sock包括eps[]数组,数组中保存的nn_ep代表连接的endpoint,因此nn_sock支持多个连接。
- nn_usock拥有原始socket。它引用nn_work,还定义了connecting, connected, accept, send, recv, stop等一系列任务。这些任务可以在nn_work的线程中异步执行。
- 在全局数组nn_transports[]中保存了所有传输协议对象的创建信息nn_transport。nn_global_create_ep()根据调用者指定的传输协议类型,查找对应的nn_transport。这里找到的是nn_ipc。
- nn_ep调用nn_transport.bind()创建nn_bipc对象,这里是nn_ipc_bind()。nn_bipc保存在成员tran中。nn_bipc包括一个nn_usock实例,这个实例将被绑定在指定的地址上以便接受连接。“bipc”中的b像是“bound”的意思。
- nn_bipc接受的连接保存在nn_aipc实例中,nn_bipc的aipcs[]数组可以保存多个实例。
- nn_aipc也包括一个nn_usock,其中包括它自己的原始socket。nn_aipc的成员listener指向nn_bipc的nn_usock实例。nn_aipc调用nn_usock_swap_owner()接管listener,并调用accept()接受连接。“aipc”中的a像是“accepted”的意思。
- nn_aipc包括一个nn_sipc实例。在原始socket配置完成后,后续工作将转移到sipc上,nn_aipc的nn_usock也将被sipc接管。“sipc”中的s像是established或stream的意思。
- nn_sipc包括一个nn_streamerhdr实例。nn_sipc委托nn_streamerhdr完成通信两端的身份认证工作,在这期间nn_usock将被nn_streamhdr托管。
- nn_streamhdr包括一个nn_timer实例。后者将处理认证超时的检测工作。nn_timer也有一个nn_worker的引用,检测工作是异步进行的。
与client端连接完成后,还有一件事,就是关联底层传输协议对象和上层协议对象,打通两者之间的数据通道。这个通道就是nn_sipc的成员nn_pipebase。
- nn_sipc初始化nn_pipebase时,将自己的函数集(nn_sipc_pipebase_vfptr,包括发送和接收),绑定到nn_pipebase的vfptr成员上。
- 调用nn_sockbase_ptr->add(),将nn_pipebase传给nn_xpub,并保存在outpipes成员中。
2. Client端 (xsub)
2.1 nn_socket()
nn_socket()创建一个nn_sock。不同于Server端的是,nn_sock的nn_sockbase指针指向nn_xsub。
2.2 nn_setsockopt()
nn_setsockopt()设置nn_sock的选项,这个选项针对底层的原始socket,也可能针对nn_xsub。比如,nn_xsub支持消息过滤,nn_sockopt()可以设置过滤条件。
2.3 nn_connect()
nn_connect()将根据指定的底层协议,初始化一系列的底层对象,并连接到指定地址的server端。
这个过程中创建的对象包括:
- nn_sock包括eps[]数组。nn_ep创建nn_cipc,保存在成员tran中,这与server端不同。
- nn_cipc包括nn_usock,其中包括它自己的原始socket。“cipc”中的c像是“connect”的意思。
- nn_cipc包括一个nn_sipc。在nn_cipc的原始socket连接成功后,后续工作将转移到sipc上,其nn_usock也被sipc接管。后面的工作就与server端的sipc一样了。
与server端连接成功后,还要关联底层传输协议对象和上层协议对象,这次sipc的成员nn_pipebase会连接到nn_xsub。
相关链接
nanomsg 1.1.5 源代码分析 (一)
nanomsg 1.1.5 源代码分析 (二)
nanomsg 1.1.5 源代码分析 (三)
nanomsg 1.1.5 源代码分析 (四)