2015-06-19 325 views
1

我們試圖應用基於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 *'作爲第二個參數。 –

回答

6

可能的錯誤是sendto行和recvfrom上面幾行的組合。

你正在做的是,你重複使用recvfrom給你的sockaddr發送回覆(在這種情況下爲ACK)。這是絕對合法和正確的,你還可以通過無連接協議向其他人發送回覆(你沒有其他方式知道該向誰發送答案,也沒有其他協議版本!)。

但是:當你正確提供&cliAddrLenrecvfrom,因此它可以返回已寫入緩衝區echoClntAddr實際地址長度(這可能會改變,想到的IPv4 VS IPv6地址),你再打sendtosizeof(echoClntAddr)作爲地址字段的大小。
由於echoClntAddr很可能是sockaddr_storage(它應該是,無論如何),它的大小將比任何有效協議的地址大小都大。因此,這是一個無效的論點。或者說,地址是。

您應該撥打sendtocliAddrLen(並在致電recvfrom之前初始化cliAddrLensizeof(echoClntAddr))。

1

而且要非常小心,你通過有效的,現有的IP地址綁定()的參數: echoServAddr.sin_addr.s_addr

如果沒有網絡接口與IP恰好暴露解決綁定在某些平臺上不會失敗(例如ESP32),但sendto()肯定會失敗。我花了2天時間來調試,我很生氣!