首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >libuv简单发送udp

libuv简单发送udp
EN

Stack Overflow用户
提问于 2020-11-20 04:57:03
回答 1查看 144关注 0票数 0

我正在用C语言做一个多平台共享库,它使用libuv发送UDP消息,但是我对libuv了解不多,也不知道我的实现是否很好,或者除了libuv之外是否还有其他解决方案。

代码语言:javascript
复制
#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;
}
EN

回答 1

Stack Overflow用户

发布于 2021-04-15 18:26:01

到目前为止,您的实现存在多个问题:

  1. 我不确定单循环迭代是否足以在每个平台上发送UDP消息。您可以使用uv_run返回的值轻松地检查这一点,使用UV_RUN_ONCE模式时请参阅uv_rundocumentation

UV_RUN_ONCE:i/o轮询一次。请注意,如果没有挂起的回调,则此函数会阻塞。完成时返回0(没有活动句柄或请求),如果预期会有更多回调,则返回或非零值(意味着您应该在将来某个时候再次运行事件循环)。

如果你想让你的代码保持原样,我建议至少这样做:

代码语言:javascript
复制
int done;
do {
    done = uv_run(loop, UV_RUN_ONCE);
} while (done != 0);

但请继续阅读,您可以做得更好!:)

  1. 这在性能方面是相当昂贵的,uv_loop应该是持久的,而不是为每条消息创建错误处理:uv_udp_binduv_udp_send,...他们可能会失败!

如何改进

我建议您更改以下两种解决方案之一的代码:

  • 你的库是在libuv上下文中使用的(也就是,你不会试图隐藏libuv实现的细节,但要求所有想要使用你的库的人显式地使用libuv。

然后,您可以将函数签名更改为类似于int send_udp(uv_loop_t *loop, char *msg)的形式,并让库用户管理事件循环并运行它。

  • 你的库使用libuv作为实现细节:你不想用libuv打扰你的库用户,因此你有责任提供健壮和高性能的代码。我是这样做的:

代码语言:javascript
复制
- `mylib_init`: starts a thread and run an `uv_loop` on it
- `send_udp`: push the message on a queue (beware of thread-safety), notify your loop it has a message to send (you can use `uv_async` for this), then you can send the message with approximately the same code you are already using.
- `mylib_shutdown`: stop the loop and the thread (again, you can use an `uv_async` to call `uv_stop` from the right thread)

它看起来像这样(我没有要测试的编译器,但您可以完成大部分工作):

代码语言:javascript
复制
static uv_thread_t thread; // our network thread
static uv_loop_t loop; // the loop running on the thread
static uv_async_t notify_send; // to notify the thread it has messages to send
static uv_async_t notify_shutdown; // to notify the thread it must shutdown
static queue_t buffer_queue; // a queue of messages to send
static uv_mutex_t buffer_queue_mutex; // to sync access to the queue from the various threads

static void thread_entry(void *arg);
static void on_send_messages(uv_async_t *handle);
static void on_shutdown(uv_async_t *handle);

int mylib_init() {
    // will call thread_entry on a new thread, our network thread
    return uv_thread_create(&thread, thread_entry, NULL);
}

int send_udp(char *msg) {
    uv_mutex_lock(&buffer_queue_mutex);

    queue_enqueue(&buffer_queue, strdup(msg)); // don't forget to free() after sending the message
    uv_async_send(&notify_send);

    uv_mutex_unlock(&buffer_queue_mutex);
}

int mylib_shutdown() {
    // will call on_shutdown on the loop thread
    uv_async_send(&notify_shutdown);

    // wait for the thread to stop
    return uv_thread_join(&thread);
}

static void thread_entry(void *arg) {
    uv_loop_init(&loop);
    uv_mutex_init_recursive(&buffer_queue_mutex);
    uv_async_init(&loop, &notify_send, on_send_messages);
    uv_async_init(&loop, &notify_shutdown, on_shutdown);

    uv_run(&loop, UV_RUN_DEFAULT); // this code will not return until uv_stop is called

    uv_mutex_destroy(&buffer_queue_mutex);
    uv_loop_close(&loop);
}

static void on_send_messages(uv_async_t *handle) {
    uv_mutex_lock(&buffer_queue_mutex);

    char *msg = NULL;
    // for each member of the queue ...
    while (queue_dequeue(&buffer_queue, &msg) == 0) {
        // create a uv_udp_t, send the message
    }

    uv_mutex_unlock(&buffer_queue_mutex);
}

static void on_shutdown(uv_async_t *handle) {
    uv_stop(&loop);
}

开发或查找队列实现由您决定;)

用法

代码语言:javascript
复制
int main() {
    mylib_init();

    send_udp("my super message");
    
    mylib_shutdown();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64919871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档