关于libuv udp echo服务器

时间:2018-04-19 12:19:31

标签: c network-programming udp libuv

我尝试过使用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) 

1 个答案:

答案 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通过邮件列表回复。