我尝试过使用libuv的简单udp echo服务器。如果我回写句柄是success.libuv on_recv再次调用NULL addr值,之后该服务器将崩溃。请找到我的示例代码并提供有价值的解决方案。 (libuv版本是libuv-v1.20.1)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uv.h"
#define CHECK(r, msg) \
if (r<0) { \
fprintf(stderr, "%s: %s\n", msg, uv_strerror(r)); \
exit(1); \
}
static uv_loop_t *uv_loop;
static uv_udp_t recv_socket;
void on_send(uv_udp_send_t *req, int status) {
if (status) {
fprintf(stderr, "Send error %s\n", uv_strerror(status));
return;
}
printf("send called\n");
}
static void on_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) {
if(addr == NULL || nread == 0){
printf("addr is null addr: [%p], nread: [%d]\n", addr, nread);
return;
}
printf("called next on rcv\n");
if (nread > 0) {
printf("%lu\n",nread);
printf("%s",rcvbuf->base);
}
printf("free :%lu %p handle: %p \n",rcvbuf->len,rcvbuf->base, handle);
free(rcvbuf->base);
uv_udp_send_t send_req;
char sender[17] = "";
struct sockaddr snd_addr;
uv_buf_t sndbuf = uv_buf_init("PONG",4);
uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
fprintf(stderr, "Recv from %s\n", sender);
if(uv_udp_send(&send_req, handle, (const struct uv_buf_t *)&sndbuf, 1, (const struct sockaddr *)addr, on_send))
{
printf("error\n");
}
printf("send success\n");
return;
}
static void on_alloc(uv_handle_t* client, size_t suggested_size, uv_buf_t* buf) {
if(suggested_size <= 0){
printf("0 size recieved\n");
return;
}
buf->base = malloc(suggested_size);
buf->len = suggested_size;
memset(buf->base, 0x00, suggested_size);
printf("malloc:%lu %p\n",buf->len,buf->base);
}
int main(int argc,char *argv[]) {
int status;
struct sockaddr_in addr;
struct sockaddr_in saddr;
printf("version: %s\n", uv_version_string());
uv_loop = uv_default_loop();
//recv socket
status = uv_udp_init(uv_loop,&recv_socket);
CHECK(status,"init");
uv_ip4_addr("0.0.0.0", 11000, &addr);
status = uv_udp_bind(&recv_socket, (const struct sockaddr*)&addr,UV_UDP_REUSEADDR);
CHECK(status,"bind");
status = uv_udp_recv_start(&recv_socket, on_alloc, on_recv);
CHECK(status,"recv");
printf("server sock: rcv %p\n", &recv_socket);
uv_run(uv_loop, UV_RUN_DEFAULT);
return 0;
}
我曾经使用以下命令连接服务器。 $ nc -u 127.0.0.1 11000
Program received signal SIGSEGV, Segmentation fault.
0x0012af4a in uv__udp_run_completed (handle=0x80491a0) at src/unix/udp.c:100
100 QUEUE_REMOVE(q);
(gdb) bt
#0 0x0012af4a in uv__udp_run_completed (handle=0x80491a0) at src/unix/udp.c:100
#1 0x0012b111 in uv__udp_io (loop=0x132800, w=0x80491e0, revents=4) at src/unix/udp.c:146
#2 0x0011da69 in uv__run_pending (loop=0x132800, mode=UV_RUN_DEFAULT) at src/unix/core.c:778
#3 uv_run (loop=0x132800, mode=UV_RUN_DEFAULT) at src/unix/core.c:360
#4 0x08048bf2 in main (argc=1, argv=0xbffffa14) at test-udp.c:108
(gdb)
答案 0 :(得分:1)
在下面找到,完美的答案是,
uv_udp_send_t send_req;
char sender[17] = "";
struct sockaddr snd_addr;
uv_buf_t sndbuf = uv_buf_init("PONG",4);
uv_ip4_name((const struct sockaddr_in*) addr, sender, 16);
终身问题:你需要在堆上而不是堆栈上分配send_req
。本答案由Ben Noordhuis通过邮件列表回复。