C libuv简单发送udp
我正在用C编写一个多平台共享库,它使用libuv发送UDP消息,但是我对libuv知之甚少,也不知道我的实现是否良好,或者除了libuv之外是否还有其他解决方案C libuv简单发送udp,c,udp,libuv,C,Udp,Libuv,我正在用C编写一个多平台共享库,它使用libuv发送UDP消息,但是我对libuv知之甚少,也不知道我的实现是否良好,或者除了libuv之外是否还有其他解决方案 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <uv.h> #define IP "0.0.0.0" #define PORT 8090 #define STR_BUFFER 2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <uv.h>
#define IP "0.0.0.0"
#define PORT 8090
#define STR_BUFFER 256
void on_send(uv_udp_send_t *req, int status) {
if (status) {
fprintf(stderr, "Send error %s\n", uv_strerror(status));
return;
}
}
int send_udp(char *msg){
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop);
uv_udp_t send_socket;
uv_udp_init(loop, &send_socket);
struct sockaddr_in send_addr;
uv_ip4_addr(IP, PORT, &send_addr);
uv_udp_bind(&send_socket, (const struct sockaddr*)&send_addr, 0);
char buff[STR_BUFFER];
memset(buff,0,STR_BUFFER);
strcpy(buff,msg);
uv_buf_t buffer = uv_buf_init(buff,STR_BUFFER);
uv_udp_send_t send_req;
uv_udp_send(&send_req, &send_socket, &buffer, 1, (const struct sockaddr*)&send_addr, on_send);
uv_run(loop, UV_RUN_ONCE);
uv_loop_close(loop);
free(loop);
return 0;
}
int main() {
send_udp("test 123\n");
return 0;
}
#包括
#包括
#包括
#包括
#定义IP“0.0.0.0”
#定义端口8090
#定义STR_缓冲区256
发送时无效(uv\U udp\U发送请求,int状态){
如果(状态){
fprintf(标准,“发送错误%s\n”,uv_strerror(状态));
返回;
}
}
int send_udp(字符*msg){
uv_loop_t*loop=malloc(sizeof(uv_loop_t));
uv_loop_init(循环);
uv_udp_t发送_套接字;
uv_udp_init(循环和发送_套接字);
发送地址中的结构sockaddr\u;
uv_ip4_地址(IP、端口和发送地址);
uv_udp_绑定(&send_socket,(const struct sockaddr*)&send_addr,0);
字符buff[STR_BUFFER];
memset(buff,0,STR_缓冲区);
strcpy(浅黄色,味精);
uv_buf_t buffer=uv_buf_init(buff,STR_buffer);
uv_udp_发送_t发送_请求;
uv_udp_send(&send_req,&send_socket,&buffer,1,(const struct sockaddr*)和send_addr,on_send);
uv_运行(循环,uv_运行一次);
uv_回路_闭合(回路);
自由(循环);
返回0;
}
int main(){
发送udp(“测试123\n”);
返回0;
}
到目前为止,您的实施存在多个问题:
uv\u运行一次
模式时,您可以使用uv\u运行
返回的值轻松检查这一点:UV\u运行一次
:轮询i/o一次。请注意,如果没有挂起的回调,则此函数将阻塞。完成时返回零(没有剩余的活动句柄或请求),或者如果需要更多回调,则返回非零(这意味着您应该在将来某个时候再次运行事件循环)
如果您希望代码保持原样,我建议您至少执行以下操作:
int完成;
做{
完成=uv_运行(循环,uv_运行一次);
}while(完成!=0);
但是继续读下去,你可以做得更好
uv_循环
s应该是持久的,而不是为每个发送的消息创建uv\u udp\u bind
,uv\u udp\u send
。。。他们可能会失败李>
如何改进
我建议您更改以下两种解决方案之一的代码:
- 您的库是在libuv上下文中使用的(也就是说,您不会试图隐藏libuv实现细节,而是要求所有希望使用您的库的人明确使用libuv。
然后,您可以将函数签名更改为
,并让库用户管理事件循环并运行它int send\u udp(uv\u loop\u t*loop,char*msg)
- 您的库使用libuv作为实现细节:您不想用libuv打扰库用户,因此您有责任提供健壮且性能良好的代码。我将这样做:
:启动线程并在其上运行mylib_init
uv_循环
:将消息推送到队列上(注意线程安全),通知您的循环它有消息要发送(您可以使用send_udp
),然后您可以使用与您已经使用的代码大致相同的代码发送消息uv_async
:停止循环和线程(同样,您可以使用mylibu shutdown
从右线程调用uv\u async
)uv\u stop
static uv\u thread\u t thread;//我们的网络线程
静态uv_循环\u t循环;//线程上运行的循环
static uv\u async\u t notify\u send;//通知它有消息要发送的线程
static uv\u async\u t notify\u shutdown;//要通知线程,它必须关闭
静态队列\u t缓冲区\u队列;//要发送的消息队列
静态uv_mutex_t buffer_queue_mutex;//从各个线程同步对队列的访问
静态无效线程输入(无效*arg);
发送消息时静态无效(uv异步句柄);
关闭时静态无效(uv异步句柄);
int mylib_init(){
//将调用新线程(我们的网络线程)上的线程\u条目
返回uv\u thread\u create(&thread,thread\u条目,NULL);
}
int send_udp(字符*msg){
uv_互斥锁(缓冲区_队列_互斥锁);
queue_enqueue(&buffer_queue,strdup(msg));//发送消息后不要忘记释放()
uv\u异步发送(¬ify\u发送);
uv_互斥锁_解锁(&buffer_queue_mutex);
}
int mylib_关机(){
//将在循环线程上调用\u shutdown
uv\u异步\u发送(&通知\u关闭);
//等待线程停止
返回uv螺纹连接(&thread);
}
静态无效线程\u条目(无效*arg){
uv_loop_init(&loop);
uv_互斥体_init_递归(&buffer_queue_mutex);
uv_async_init(&loop,¬ify_send,on_send_消息);
uv_async_init(&loop,¬ify_shutdown,on_shutdown);
uv_run(&loop,uv_run_DEFAULT);//在调用uv_stop之前,此代码不会返回
uv_互斥体_销毁(&缓冲区_队列_互斥体);
uv_回路_闭合(&loop);
}
发送消息时静态无效(uv异步句柄){
uv_互斥锁(缓冲区_队列_互斥锁);
char*msg=NULL;
//对于队列的每个成员。。。
while(queue\u dequeue(&buffer\u queue,&msg)==0){
//创建一个uv\u udp\t,发送消息
}
uv_互斥锁_解锁(&buffer_queue_mutex);
}
关闭时静态无效(uv异步句柄){
uv_停止(&循环);
}
由您自行开发或找到队列实现;)
用法
intmain(){
mylib_init();
发送udp(“我的超级消息”);
mylib_shutdown();
}