UDP sendto() 错误:参数无效 [英] UDP sendto() error: invalid argument
问题描述
我们正在尝试应用基于 UDP 的协议,但在使用 sendto() 函数时遇到了一些问题.
当我们尝试用 ack 响应写请求时,我们从 sendto() 函数中得到无效参数"
这是我们的代码:
int 袜子;//插座sockaddr_in_t echoServAddr;//本地地址sockaddr_in_t echoClntAddr;//客户端地址无符号整数 cliAddrLen;//传入消息的长度data_packet_t echoBuffer;wrq_packet_t wrqBuffer;无符号短 echoServPort;//服务器端口int recvMsgSize;//接收消息的大小ack_packet_t 确认;struct timeval 超时;fd_set fds;/* 创建用于发送/接收数据报的套接字 */if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) <0) perror("TTFTPERROR: socket() failed");/* 构造本地地址结构 */memset(&echoServAddr, 0, sizeof(echoServAddr));echoServAddr.sin_family = AF_INET;echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);echoServAddr.sin_port = htons(echoServPort);/*绑定到本地地址*/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;而 (1) {recvMsgSize = recvfrom(sock, &wrqBuffer, FULL_PACKET_SIZE, 0, (struct sockaddr *) &echoClntAddr, &cliAddrLen);如果 (recvMsgSize > 0) 中断;//我们得到了一些东西!}Ack = CreateAckPacket(0);//发送确认 0if (sendto(sock, &Ack, sizeof(Ack), 0, (struct sockaddr *) &echoClntAddr, sizeof(echoClntAddr)) == -1){perror("TTFTPERROR: sendto() 发送 ack 0 失败");退出(-1);}
您能帮助我们了解哪里出了问题吗?
可能的错误是 sendto
行和 recvfrom
上面几行的组合.>
您正在做的是,您重用 recvfrom
给您的 sockaddr 发送回复(在本例中为 ACK).这是绝对合法和正确的,否则你怎么能用无连接协议向某人发送回复(你没有其他方式知道将答案发送给谁,也不知道使用什么协议版本!).
但是:虽然您正确提供了 &cliAddrLen
到 recvfrom
以便它可以返回实际地址长度(可能会有所不同,想想 IPv4 与 IPv6 地址)写入缓冲区 echoClntAddr
,您稍后使用 sizeof(echoClntAddr)
调用 sendto
作为地址字段的大小.
由于 echoClntAddr
很可能是一个 sockaddr_storage
(它应该是,无论如何),它的大小将大于任何有效协议的地址大小.因此,这是一个无效的论点.或者更确切地说,地址是.
您应该改为使用 cliAddrLen
调用 sendto
(并在调用之前将 cliAddrLen
初始化为 sizeof(echoClntAddr)
recvfrom
).
We are trying to apply a UDP based protocol and having some problem with sendto() function.
when we try to response to the write-request with ack we get "invalid argument" from the sendto() function
this is our code:
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);
}
Could you help us understand what is wrong?
The likely error is a combination of the sendto
line and recvfrom
a few lines above.
What you are doing is, you reuse the sockaddr that recvfrom
gave you to send a reply (ACK in this case). That is absolutely legitimate and correct, how else could you send a reply to someone on a connectionless protocol (you have no other way of knowing whom to send the answer to, nor with what protocol version!).
But: While you correctly provide &cliAddrLen
to recvfrom
so it can return the actual address length (which may vary, think of IPv4 vs IPv6 addresses) that was written into the buffer echoClntAddr
, you later call sendto
with sizeof(echoClntAddr)
as the size of the address field.
Since echoClntAddr
is most likely a sockaddr_storage
(it should be, anyway), its size will be larger than any valid protocol's address size. Thus, it's an invalid argument. Or rather, the address is.
You should instead call sendto
with cliAddrLen
(and initialize cliAddrLen
to sizeof(echoClntAddr)
prior to calling recvfrom
).
这篇关于UDP sendto() 错误:参数无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!