首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UDP sendto()错误:参数无效

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

Stack Overflow用户
提问于 2015-06-19 22:49:39
回答 2查看 13.5K关注 0票数 5

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

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

这是我们的代码:

代码语言:javascript
复制
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);
}

你能帮我们了解一下哪里出了问题吗?

EN

回答 2

Stack Overflow用户

发布于 2015-06-19 23:10:17

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

您正在做的是,重用recvfrom提供给您的sockaddr来发送回复(在本例中为ACK)。这绝对是合法和正确的,否则您如何在无连接协议上向某人发送回复(您没有其他方法知道要将答案发送给谁,也无法知道使用什么协议版本!)。

但是:虽然您正确地向recvfrom提供了&cliAddrLen,以便它可以返回写入到缓冲区echoClntAddr中的实际地址长度(考虑IPv4和IPv6地址,该长度可能会有所不同),但您稍后将使用sizeof(echoClntAddr)作为地址字段的大小来调用sendto

因为echoClntAddr很可能是一个sockaddr_storage (无论如何都应该是),所以它的大小将大于任何有效协议的地址大小。因此,这是一个无效的参数。更确切地说,地址是。

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

票数 10
EN

Stack Overflow用户

发布于 2017-07-07 02:39:17

还要非常小心地将有效的和现有的IP地址传递给绑定()的参数: echoServAddr.sin_addr.s_addr

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30941151

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档