服务器端的建立流程如下
- uv_tcp_init建立tcp句柄。
- uv_tcp_bind绑定。
- uv_listen建立监听,当有新的连接到来时,激活调用回调函数。
- uv_accept接收链接。
- 使用stream处理来和客户端通信。
uv_tcp_bind
- uv_tcp_t* handle
- sockaddr* addr 代表端口号和ip地址的结构体
- flags 使用ipv4的时候传递0,使用ipv6的时候用uv_tcp_flags的UV_TCP_IPV6ONLY 也就是1
uv_listen
- uv_stream_t* stream 双工通道的抽象类,有三个实现
uv_tcp_t
,uv_pipe_t
和uv_tty_t
. - int backlog 表示accept queue的大小,如果达到这个值,server将发送一个ECONNREFUSED错误信息。实际操作中,内核会根据传入的backlog参数与系统参数somaxconn,取二者的较小值
- uv_connection_cb 回调函数
uv_accept
- uv_stream_t* server
- uv_stream_t* client
uv_read_start
- uv_stream_t* client
- uv_alloc_cb alloc_cb 为每个数据包分配内存
- uv_read_cb read_cb 读取数据后的回调函数
回调函数uv_alloc_cb
参数:
- uv_handle_t *handle 与客户端建立的链接的句柄
- size_t suggested_size 估计的数据包的大小
- uv_buf_t *buf 数据存放的位置
typedef struct uv_buf_t {
char* base;
size_t len;
} uv_buf_t;
回调函数 uv_read_cb
参数:
- uv_stream_t *client 与客户端建立的链接句柄
- ssize_t nread 本次读取数据的大小
- uv_buf_t *buf 数据存放位置
这里需要注意buf用完后要手动free掉,不要
uv_buf_init函数只把指针拷贝到结构体中,没有复制里面的内容。详见:https://stackoverflow.com/questions/38081423/libuv-and-uv-buf-init-who-should-free-what