UDP sendto() 错误:参数无效 [英] UDP sendto() error: invalid argument

查看:38
本文介绍了UDP sendto() 错误:参数无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在尝试应用基于 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).这是绝对合法和正确的,否则你怎么能用无连接协议向某人发送回复(你没有其他方式知道将答案发送给谁,也不知道使用什么协议版本!).

但是:虽然您正确提供了 &cliAddrLenrecvfrom 以便它可以返回实际地址长度(可能会有所不同,想想 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆