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
原创粉丝点击