综述
使用uv_udp_init()
分别初始化得到uv_udp_t
类型的接收和发送的UDP套接字udp_recv_socket
, udp_send_socket
。
使用uv_udp_bind()
函数,将套接字绑定到本机,端口设置为0则由系统分配。
使用uv_udp_connect()
函数,给套接字连接一个远程地址,则调用uv_udp_send()
函数发送信息时,不需要指定远程地址。
代码
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>
/// For detect memory leaky.
#ifdef _WIN32
#include <crtdbg.h>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
#endif
/// For ntohs()
#pragma comment(lib,"ws2_32.lib")
uv_udp_t udp_recv_socket, udp_send_socket;
uv_udp_send_t send_req;
struct sockaddr_in recv_addr, send_addr;
uv_buf_t read_buf;
uint64_t bytes_recv = 0;
uint64_t bytes_send = 0;
uv_timer_t timer_req;
void alloc_uv_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
void on_udp_send(uv_udp_send_t *req, int status) {
bytes_send += ((uv_buf_t *)req->data)->len;
free(((uv_buf_t *)req->data)->base);
if (status) {
fprintf(stderr, "Send error %s\n", uv_strerror(status));
return;
}
}
void on_udp_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags)
{
if (nread < 0)
{
free(buf->base);
fprintf(stderr, "Read error %s\n", uv_err_name(nread));
uv_close((uv_handle_t*)req, NULL);
uv_close((uv_handle_t*)&udp_send_socket, NULL);
uv_timer_stop(&timer_req);
return;
}
if (nread == 0)
{
free(buf->base);
return;
}
bytes_recv += nread;
read_buf.base = buf->base;
read_buf.len = nread;
send_req.data = (void *)&read_buf;
uv_udp_send(&send_req, &udp_send_socket, &read_buf, 1, NULL, on_udp_send);
}
void on_time_out(uv_timer_t* handle)
{
fprintf(stdout, "Recv bytes: %llu\t", bytes_recv);
fprintf(stdout, "Send bytes: %llu\r", bytes_send);
fflush(stdout);
}
int main()
{
auto loop = uv_default_loop();
uv_udp_init(loop, &udp_send_socket);
uv_ip4_addr("127.0.0.1", 8666, &send_addr);
uv_udp_connect(&udp_send_socket, (const struct sockaddr *)&send_addr);
uv_udp_init(loop, &udp_recv_socket);
uv_ip4_addr("0.0.0.0", 0, &recv_addr);
uv_udp_bind(&udp_recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR);
uv_udp_recv_start(&udp_recv_socket, alloc_uv_buffer, on_udp_read);
int namelen = 40;
// struct sockaddr_in real_addr;
int ret = uv_udp_getsockname(&udp_recv_socket, (struct sockaddr *)&recv_addr, &namelen);
if (ret != 0) {
printf("couldn't get sock name\n");
}
printf("listening on port %d\n", ntohs(recv_addr.sin_port));
uv_timer_init(loop, &timer_req);
uv_timer_start(&timer_req, on_time_out, 1000, 1000);
int res = uv_run(loop, UV_RUN_DEFAULT);
/// For detect memory leaky.
#ifdef _WIN32
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);
#endif
return res;
}