我正在用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 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;
}发布于 2021-04-15 18:26:01
到目前为止,您的实现存在多个问题:
uv_run返回的值轻松地检查这一点,使用UV_RUN_ONCE模式时请参阅uv_run的documentation:
UV_RUN_ONCE:i/o轮询一次。请注意,如果没有挂起的回调,则此函数会阻塞。完成时返回0(没有活动句柄或请求),如果预期会有更多回调,则返回或非零值(意味着您应该在将来某个时候再次运行事件循环)。
如果你想让你的代码保持原样,我建议至少这样做:
int done;
do {
done = uv_run(loop, UV_RUN_ONCE);
} while (done != 0);但请继续阅读,您可以做得更好!:)
uv_loop应该是持久的,而不是为每条消息创建错误处理:uv_udp_bind,uv_udp_send,...他们可能会失败!如何改进
我建议您更改以下两种解决方案之一的代码:
然后,您可以将函数签名更改为类似于int send_udp(uv_loop_t *loop, char *msg)的形式,并让库用户管理事件循环并运行它。
- `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)它看起来像这样(我没有要测试的编译器,但您可以完成大部分工作):
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(¬ify_send);
uv_mutex_unlock(&buffer_queue_mutex);
}
int mylib_shutdown() {
// will call on_shutdown on the loop thread
uv_async_send(¬ify_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, ¬ify_send, on_send_messages);
uv_async_init(&loop, ¬ify_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);
}开发或查找队列实现由您决定;)
用法
int main() {
mylib_init();
send_udp("my super message");
mylib_shutdown();
}https://stackoverflow.com/questions/64919871
复制相似问题