UDP sendto()错误:无效的参数

问题描述:

我们试图应用基于UDP的协议,并在sendto()函数中遇到了一些问题。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); 
} 

你能帮助我们理解是错的?

+0

什么是错误/错误代码? – Samer

+0

22,错误是“无效参数” – user3350919

+0

@szczurcio:这将是一个编译器错误,而不是运行时错误。但是我知道[sendto()'](http://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html)采用了'const void *'作为第二个参数。 –

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

你正在做的是,你重复使用recvfrom给你的sockaddr发送回复(在这种情况下为ACK)。这是绝对合法和正确的,你还可以通过无连接协议向其他人发送回复(你没有其他方式知道该向谁发送答案,也没有其他协议版本!)。

但是:当你正确提供&cliAddrLenrecvfrom,因此它可以返回已写入缓冲区echoClntAddr实际地址长度(这可能会改变,想到的IPv4 VS IPv6地址),你再打sendtosizeof(echoClntAddr)作为地址字段的大小。
由于echoClntAddr很可能是sockaddr_storage(它应该是,无论如何),它的大小将比任何有效协议的地址大小都大。因此,这是一个无效的论点。或者说,地址是。

您应该拨打sendtocliAddrLen(并在致电recvfrom之前初始化cliAddrLensizeof(echoClntAddr))。

而且要非常小心,你通过有效的,现有的IP地址绑定()的参数: echoServAddr.sin_addr.s_addr

如果没有网络接口与IP恰好暴露解决绑定在某些平台上不会失败(例如ESP32),但sendto()肯定会失败。我花了2天时间来调试,我很生气!