эхо-сервер libuv udp относительно

Я пробовал использовать простой эхо-сервер udp, используя libuv. если я вернусь к дескриптору, это будет успешно. 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) 

person Ramesh    schedule 19.04.2018    source источник


Ответы (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 в куче, а не в стеке. На этот ответ ответил Бен Нордхуис через список рассылки.

person Ramesh    schedule 20.04.2018