UDP sendto()错误:参数无效

时间:2015-06-19 14:49:39

标签: c udp

我们正在尝试应用基于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);
}

你能帮我们理解什么是错的吗?

2 个答案:

答案 0 :(得分:6)

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

您正在做的是,您重复使用recvfrom发送回复的sockaddr(在这种情况下为ACK)。这绝对是合法和正确的,你怎么能在无连接协议上向某人发送回复(你没有其他方式知道发送答案的人,也没有协议版本!)。

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

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

答案 1 :(得分:2)

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

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