【问题标题】:UDP sendto() error: invalid argumentUDP sendto() 错误:参数无效
【发布时间】:2017-07-07 02:39:17
【问题描述】:

我们正在尝试应用基于 UDP 的协议,但 sendto() 函数存在一些问题。

当我们尝试使用 ack 响应写入请求时,我们从 sendto() 函数中得到“无效参数”

这是我们的代码:

int                sock;                  // Socket 
sockaddr_in_t      echoServAddr;          // Local address 
sockaddr_in_t      echoClntAddr;          // Client address 
unsigned int       cliAddrLen;            // Length of incoming message
data_packet_t      echoBuffer;
wrq_packet_t       wrqBuffer;
unsigned short     echoServPort;          // Server port 
int                recvMsgSize;           // Size of received message 
ack_packet_t      Ack;
struct timeval     timeout;
fd_set             fds;



/* Create socket for sending/receiving datagrams */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) perror("TTFTPERROR: socket() failed"); 

/* Construct local address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr));
echoServAddr.sin_family = AF_INET;
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
echoServAddr.sin_port = htons(echoServPort);

/*Bind to the local address */
if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) perror("TTFTPERROR: bind() failed");

FD_ZERO(&fds);
FD_SET(sock, &fds);
timeout.tv_sec = WAIT_FOR_PACKET_TIMEOUT;
timeout.tv_usec = 0;

while (1) {
    recvMsgSize = recvfrom(sock, &wrqBuffer, FULL_PACKET_SIZE, 0, (struct sockaddr *) &echoClntAddr, &cliAddrLen);
    if (recvMsgSize > 0) break; // we got something!
}

Ack = CreateAckPacket(0); // send ack 0
if (sendto(sock, &Ack, sizeof(Ack), 0, (struct sockaddr *) &echoClntAddr, sizeof(echoClntAddr)) == -1){
    perror("TTFTPERROR: sendto() failed to send ack 0");
    exit(-1);
}

您能帮助我们了解问题所在吗?

【问题讨论】:

  • 错误/错误代码是什么?
  • 22,错误是“无效参数”
  • @szczurcio:那将是编译器错误,而不是运行时错误。但是我知道的sendto()const void * 作为第二个参数。
  • @MartinR 我认为 OP 意味着编译器错误,我想应该在问题中澄清。好吧,这取决于环境,Windows API 采用 const char*: msdn.microsoft.com/en-us/library/windows/desktop/…
  • @user3350919 您正在使用-Wall 进行编译,对吗?这至少应该给你一个警告。

标签: c udp


【解决方案1】:

可能的错误是sendto 行和recvfrom 以上几行的组合。

您正在做的是,您重用 recvfrom 给您的 sockaddr 来发送回复(在这种情况下为 ACK)。这是绝对合法和正确的,否则你怎么能通过无连接协议向某人发送回复(你无法知道将答案发送给谁,也不知道使用什么协议版本!)。

但是:当您正确提供 &amp;cliAddrLenrecvfrom 时,它可以返回实际地址长度(可能会有所不同,请考虑 IPv4 与 IPv6 地址)已写入缓冲区echoClntAddr,您稍后调用sendto 并使用sizeof(echoClntAddr) 作为地址字段的大小。
由于echoClntAddr 很可能是sockaddr_storage(无论如何应该是),它的大小将大于任何有效协议的地址大小。因此,这是一个无效的论点。或者更确切地说,地址是。

您应该改为使用cliAddrLen 调用sendto(并在调用recvfrom 之前将cliAddrLen 初始化为sizeof(echoClntAddr))。

【讨论】:

    【解决方案2】:

    还要非常小心地将 VALID 和 EXISTING IP 地址传递给 bind() 的参数: echoServAddr.sin_addr.s_addr

    如果您没有使用该确切 IP 地址公开的网络接口,则绑定在某些平台(例如 ESP32)上不会失败,但 sendto() 肯定会失败。我花了 2 天时间调试它,我很生气!

    【讨论】:

      猜你喜欢
      • 2018-06-16
      • 2018-10-11
      • 2020-09-16
      • 2014-01-04
      • 1970-01-01
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      • 2016-01-07
      相关资源
      最近更新 更多