【问题标题】:Sockets sendto() returns EINVAL after previous successful call套接字 sendto() 在上一次成功调用后返回 EINVAL
【发布时间】:2018-02-11 19:10:41
【问题描述】:

我修改了thisC 数据报(UDP)套接字客户端示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>

#define SERVERPORT "4950"

volatile sig_atomic_t is_shutdown = 0;

void handler_signal(int signal)
{
    if (signal == SIGINT)
    {
        is_shutdown = 1;
    }
}

int main(int argc, char *argv[])
{
    int socket_fd;
    struct addrinfo hints, *server_info, *temp;
    int result;
    int number_bytes;

    if (argc != 2)
    {
        fprintf(stderr, "usage: executable [hostname]\n");
        return 1;
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    result = getaddrinfo(argv[1], SERVERPORT, &hints, &server_info);

    if (result != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
        return 1;
    }

    // loop through all the results and make a socket
    for(temp = server_info; temp != NULL; temp = temp->ai_next)
    {
        socket_fd = socket(temp->ai_family, temp->ai_socktype, temp->ai_protocol);

        if (socket_fd == -1)
        {
            fprintf(stderr, "socket error: %s\n", strerror(errno));
            continue;
        }

        break;
    }

    freeaddrinfo(server_info);

    if (temp == NULL)
    {
        fprintf(stderr, "failed to create socket\n");
        return 2;
    }

    //int hostname_length = strlen(argv[2]);
    unsigned long counter = 0;
    const size_t buffer_length = 50;
    char buffer[buffer_length];
    memset(&buffer, 0, buffer_length);

    while (!is_shutdown)
    {
        snprintf(buffer, buffer_length, "%lu", counter++);

        number_bytes = sendto(socket_fd, buffer, buffer_length, 0, temp->ai_addr, temp->ai_addrlen);

        if (number_bytes == -1)
        {
            fprintf(stderr, "sendto error: %s\n", strerror(errno));
            break;
        }

        printf("sent %d bytes to %s.\n", number_bytes, argv[1]);
    }

    result = close(socket_fd);

    if (result == -1)
    {
        fprintf(stderr, "close error: %s\n", strerror(errno));
    }

    printf("exiting application\n");

    return 0;
}

在循环的第二次迭代中,sendto 函数使用 Invalid argument (errno 22) 失败。它适用于第一个。

但是,如果我将其更改为以下代码,则代码可以正常工作(客户端不断在无限循环中发送消息并且服务器成功接收它们):

    //...

    //create a copy to pass it later
    socklen_t length = temp->ai_addrlen;
    struct sockaddr *address = temp->ai_addr;

    while (!is_shutdown)
    {
        snprintf(buffer, buffer_length, "%lu", counter++);

        number_bytes = sendto(socket_fd, buffer, buffer_length, 0, address, length);

   //...

我在这里做了什么?我错过了什么?我不确定这里发生了什么。

【问题讨论】:

  • if (number_bytes == -1):: 在跳出循环之前检查 errno。可以是 EAGAIN 、 EINTR ,甚至是与 UDP 资源相关的。
  • @wildplasser 谢谢,我会修改它。但是现在它只变成了EINVAL。
  • 你回答了你自己的问题:number_bytes = sendto(socket_fd, buffer, buffer_length, 0, &amp;temp-&gt;ai_addr, temp-&gt;ai_addrlen);:地址需要通过指针传递。
  • @wildplasser 那么为什么它在第一次调用时起作用而只在第二次调用时失败? temp-&gt;ai_addr 已经是一个指针。
  • temp 是指向struct addrinfo 的指针,该值是从server_info 分配的。但是当你freeaddrinfo(server_info); 内存被释放并且temp 指向无处。它第一次工作,因为还没有发生内存重用。但是在内存重用后它变得无效。在释放结构之前尝试制作数据副本。

标签: c sockets udp datagram sendto


【解决方案1】:

正如 Frankie_C 在他的 [评论] 中指出的那样:

temp 是指向struct addrinfo 的指针,该值是从server_info 分配的。但是当你freeaddrinfo(server_info) 内存被释放并且temp 指向无处。它第一次工作,因为还没有发生内存重用。但是在内存重用后它变得无效。在释放结构之前尝试制作数据副本。

【讨论】:

    猜你喜欢
    • 2014-05-23
    • 1970-01-01
    • 2011-04-29
    • 2012-08-02
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多