libuv学习笔记(16)
来源:互联网 发布:浅谈移动通信网络优化 编辑:程序博客网 时间:2024/04/28 00:15
libuv学习笔记(16)
uv_udp_t数据结构与相关函数
数据结构
typedef struct uv_udp_s uv_udp_t;struct uv_udp_s { UV_HANDLE_FIELDS//uv_handt_t的成员 //目前等待发送的数据 size_t send_queue_size; //等待处理的发送请求 size_t send_queue_count; //UV_UDP_PRIVATE_FIELDS展开如下: SOCKET socket; unsigned int reqs_pending; int activecnt; uv_req_t recv_req;//接收请求 uv_buf_t recv_buffer;//接收的数据 struct sockaddr_storage recv_from;//数据来源的地址信息 int recv_from_len; uv_udp_recv_cb recv_cb; uv_alloc_cb alloc_cb; LPFN_WSARECV func_wsarecv;//异步函数指针 LPFN_WSARECVFROM func_wsarecvfrom;//异步函数指针};
相关函数
初始化,导出函数,uv.h中声明,udp.c中定义
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { int domain; //只是用低八位 domain = flags & 0xFF; if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) return UV_EINVAL; if (flags & ~0xFF) return UV_EINVAL; //初始化handle,将handle添加到loop的handle队列 uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP); handle->socket = INVALID_SOCKET; handle->reqs_pending = 0; handle->activecnt = 0; handle->func_wsarecv = WSARecv; handle->func_wsarecvfrom = WSARecvFrom; handle->send_queue_size = 0; handle->send_queue_count = 0; uv_req_init(loop, (uv_req_t*) &(handle->recv_req));//初始化接收请求 handle->recv_req.type = UV_UDP_RECV; handle->recv_req.data = handle; //如果有错误,移除loophandle队列中的本handle if (domain != AF_UNSPEC) {//不支持AF_UNSPEC SOCKET sock; DWORD err; sock = socket(domain, SOCK_DGRAM, 0);//获取一个socket if (sock == INVALID_SOCKET) { err = WSAGetLastError(); QUEUE_REMOVE(&handle->handle_queue); return uv_translate_sys_error(err); } err = uv_udp_set_socket(handle->loop, handle, sock, domain); if (err) { closesocket(sock); QUEUE_REMOVE(&handle->handle_queue); return uv_translate_sys_error(err); } } return 0;}
打开一个socket作为uv_udp_t,导出函数,uv.h中声明,udp.c中定义
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { WSAPROTOCOL_INFOW protocol_info; int opt_len; int err; //获取socket地址类型 opt_len = (int) sizeof protocol_info; //获取协议详细信息 if (getsockopt(sock, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &protocol_info, &opt_len) == SOCKET_ERROR) { return uv_translate_sys_error(GetLastError()); } //将socket与uv_udp_t联系起来 err = uv_udp_set_socket(handle->loop, handle, sock, protocol_info.iAddressFamily); return uv_translate_sys_error(err);}
static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, int family) { DWORD yes = 1; WSAPROTOCOL_INFOW info; int opt_len; if (handle->socket != INVALID_SOCKET) return UV_EBUSY; //socket设置为非阻塞模式 if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { return WSAGetLastError(); } if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) { return GetLastError(); } //与iocp端口联系起来 if (CreateIoCompletionPort((HANDLE)socket, loop->iocp, (ULONG_PTR)socket, 0) == NULL) { return GetLastError(); } if (pSetFileCompletionNotificationModes) { //只能在原生的udp socket上使用SetFileCompletionNotificationModes函数 opt_len = (int) sizeof info; if (getsockopt(socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) == SOCKET_ERROR) { return GetLastError(); } if (info.ProtocolChain.ChainLen == 1) {//lsp链长度为1 if (pSetFileCompletionNotificationModes((HANDLE)socket, FILE_SKIP_SET_EVENT_ON_HANDLE |//并不会改变socket句柄的状态(signal) FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {//不要将以同步方式完成的异步请求添加到与设 //备相关联的完成端口中。 handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; handle->func_wsarecv = uv_wsarecv_workaround; handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; } else if (GetLastError() != ERROR_INVALID_FUNCTION) { return GetLastError(); } } } handle->socket = socket;//与uv_udp_t联系起来 if (family == AF_INET6) { handle->flags |= UV_HANDLE_IPV6; } else { assert(!(handle->flags & UV_HANDLE_IPV6)); } return 0;}
绑定,导出函数,uv.h中声明,udp.c中定义
int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags) { unsigned int addrlen; if (handle->type != UV_UDP) return UV_EINVAL; if (addr->sa_family == AF_INET) addrlen = sizeof(struct sockaddr_in); else if (addr->sa_family == AF_INET6) addrlen = sizeof(struct sockaddr_in6); else return UV_EINVAL; //调用内部函数处理 return uv__udp_bind(handle, addr, addrlen, flags);}
uv__udp_bind调用uv_udp_maybe_bind
static int uv_udp_maybe_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen, unsigned int flags) { int r; int err; DWORD no = 0; if (handle->flags & UV_HANDLE_BOUND) return 0; if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) { //地址类型错误 return ERROR_INVALID_PARAMETER; } if (handle->socket == INVALID_SOCKET) {//没有socket就创建 SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) { return WSAGetLastError(); } //socket与handle以及iocp端口联系起来 err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family); if (err) { closesocket(sock); return err; } } if (flags & UV_UDP_REUSEADDR) { DWORD yes = 1; /* Set SO_REUSEADDR on the socket. */ if (setsockopt(handle->socket, SOL_SOCKET, SO_REUSEADDR,//允许重复绑定 (char*) &yes, sizeof yes) == SOCKET_ERROR) { err = WSAGetLastError(); return err; } } if (addr->sa_family == AF_INET6) handle->flags |= UV_HANDLE_IPV6; if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &no, sizeof no); } /绑定 r = bind(handle->socket, addr, addrlen); if (r == SOCKET_ERROR) { return WSAGetLastError(); } handle->flags |= UV_HANDLE_BOUND; return 0;}
发送数据
int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, unsigned int addrlen, uv_udp_send_cb send_cb) { const struct sockaddr* bind_addr; int err; if (!(handle->flags & UV_HANDLE_BOUND)) {//未绑定,绑定默认地址 if (addrlen == sizeof(uv_addr_ip4_any_)) { bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; } else if (addrlen == sizeof(uv_addr_ip6_any_)) { bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; } else { abort(); } err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); } err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb); if (err) return uv_translate_sys_error(err); return 0;}
发送的内部处理函数
static int uv__send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, unsigned int addrlen, uv_udp_send_cb cb) { uv_loop_t* loop = handle->loop; DWORD result, bytes; //初始化发送请求 uv_req_init(loop, (uv_req_t*) req); req->type = UV_UDP_SEND; req->handle = handle; req->cb = cb; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); //异步发送 result = WSASendTo(handle->socket, (WSABUF*)bufs, nbufs, &bytes, 0, addr, addrlen, &req->u.io.overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { //不使用iocp,直接将请求添加到loop的请求列表 req->u.io.queued_bytes = 0; handle->reqs_pending++; handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_count++; REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { //使用iocp req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);//本次发送的数据 handle->reqs_pending++; handle->send_queue_size += req->u.io.queued_bytes;//等待发送的数据 handle->send_queue_count++;//等待处理的发送请求 REGISTER_HANDLE_REQ(loop, handle, req);//注册请求 } else { return WSAGetLastError(); } return 0;}
对发送请求的处理:
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req) { int err; assert(handle->type == UV_UDP); assert(handle->send_queue_size >= req->u.io.queued_bytes); assert(handle->send_queue_count >= 1); handle->send_queue_size -= req->u.io.queued_bytes;//等待发送的数据 handle->send_queue_count--;//等待处理的请求 UNREGISTER_HANDLE_REQ(loop, handle, req);//取消请求的注册 if (req->cb) { err = 0; if (!REQ_SUCCESS(req)) { err = GET_REQ_SOCK_ERROR(req); } req->cb(req, uv_translate_sys_error(err));//回调函数 } DECREASE_PENDING_REQ_COUNT(handle);//handle活动请求递减,如果处于closing状态且活动请求为0,关闭handle}
开始读取
内部调用uv__udp_recv_start
int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) { uv_loop_t* loop = handle->loop; int err; if (handle->flags & UV_HANDLE_READING) { return WSAEALREADY; } //没绑定就绑定默认的地址 err = uv_udp_maybe_bind(handle, (const struct sockaddr*) &uv_addr_ip4_any_, sizeof(uv_addr_ip4_any_), 0); if (err) return err; handle->flags |= UV_HANDLE_READING; INCREASE_ACTIVE_COUNT(loop, handle); loop->active_udp_streams++; handle->recv_cb = recv_cb; handle->alloc_cb = alloc_cb; if (!(handle->flags & UV_HANDLE_READ_PENDING)) uv_udp_queue_recv(loop, handle);//投递接收数据的请求 return 0;}
投递请求
static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { uv_req_t* req; uv_buf_t buf; DWORD bytes, flags; int result; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); req = &handle->recv_req; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); //uv_active_udp_streams_threshold为0,不再需要预分配了 if (loop->active_udp_streams < uv_active_udp_streams_threshold) { ... } else { handle->flags |= UV_HANDLE_ZERO_READ; buf.base = (char*) uv_zero_; buf.len = 0; flags = MSG_PEEK; result = handle->func_wsarecv(handle->socket, (WSABUF*) &buf, 1, &bytes, &flags, &req->u.io.overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { //不使用iocp handle->flags |= UV_HANDLE_READ_PENDING; req->u.io.overlapped.InternalHigh = bytes; handle->reqs_pending++; uv_insert_pending_req(loop, req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { //使用iocp handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } else { //出错 SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, req); handle->reqs_pending++; } }}
对读取请求的处理
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req) { uv_buf_t buf; int partial; assert(handle->type == UV_UDP); handle->flags &= ~UV_HANDLE_READ_PENDING; if (!REQ_SUCCESS(req)) {//未成功读取 DWORD err = GET_REQ_SOCK_ERROR(req); if (err == WSAEMSGSIZE) { //包数据比缓存大 } else if (err == WSAECONNRESET || err == WSAENETRESET) { if (!(handle->flags & UV_HANDLE_ZERO_READ)) { goto done; } } else { //真正的错误 if (handle->flags & UV_HANDLE_READING) { uv_udp_recv_stop(handle);//停止接受 buf = (handle->flags & UV_HANDLE_ZERO_READ) ? uv_buf_init(NULL, 0) : handle->recv_buffer; handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); } goto done; } } if (!(handle->flags & UV_HANDLE_ZERO_READ)) { //成功读取 partial = !REQ_SUCCESS(req); handle->recv_cb(handle, req->u.io.overlapped.InternalHigh, &handle->recv_buffer, (const struct sockaddr*) &handle->recv_from, partial ? UV_UDP_PARTIAL : 0); } else if (handle->flags & UV_HANDLE_READING) { DWORD bytes, err, flags; struct sockaddr_storage from; int from_len; handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); if (buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); goto done; } assert(buf.base != NULL); memset(&from, 0, sizeof from); from_len = sizeof from; flags = 0; if (WSARecvFrom(handle->socket, (WSABUF*)&buf, 1, &bytes, &flags, (struct sockaddr*) &from, &from_len, NULL, NULL) != SOCKET_ERROR) { handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0); } else { err = WSAGetLastError(); if (err == WSAEMSGSIZE) { handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, UV_UDP_PARTIAL); } else if (err == WSAEWOULDBLOCK) { handle->recv_cb(handle, 0, &buf, NULL, 0); } else if (err == WSAECONNRESET || err == WSAENETRESET) { handle->recv_cb(handle, 0, &buf, NULL, 0); } else { uv_udp_recv_stop(handle); handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); } } }done: /* Post another read if still reading and not closing. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { uv_udp_queue_recv(loop, handle);//继续投递读取请求 } DECREASE_PENDING_REQ_COUNT(handle);}
停止读取
内部调用uv__udp_recv_stop
int uv__udp_recv_stop(uv_udp_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING;//取消接受标记 handle->loop->active_udp_streams--; DECREASE_ACTIVE_COUNT(loop, handle); } return 0;}
libuv还提供了一些组播相关的API,可以参考以下文章:
http://blog.csdn.net/langeldep/article/details/6167137
0 0
- libuv学习笔记(16)
- libuv学习笔记(2)
- libuv学习笔记(3)
- libuv学习笔记(4)
- libuv学习笔记(5)
- libuv学习笔记(6)
- libuv学习笔记(7)
- libuv学习笔记(9)
- libuv学习笔记(10)
- libuv学习笔记(11)
- libuv学习笔记(12)
- libuv学习笔记(13)
- libuv学习笔记(14)
- libuv学习笔记(17)
- libuv学习笔记(18)
- libuv学习笔记(20)
- libuv学习笔记(21)
- libuv学习笔记(22)
- BZOJ1455: 罗马游戏
- 1002 大数相加 (简单模拟) 水题
- Android中adb工具的一些简单使用
- 图片替换
- sizeof详解 字节对齐
- libuv学习笔记(16)
- HDU2199 二分查找(浮点型) 水题
- csipsimple not enough buffer for decoded frame
- javascript对象
- c++学习心得
- 1009 贪心算法 (简单分背包问题) 水题
- @meta媒体查询
- C语言基础 printf输出int型变量
- 点播时ffmpeg播放视频当几秒没有收到数据时的处理