2013-11-25 170 views
1

我試圖實現一個回聲客戶端。使用sendto()的客戶端正在傳輸消息,服務器正在接收顯示消息。但是然後服務器不發送消息(回顯)。這裏是服務器和客戶端的代碼。誰能幫我這個?迴應服務器沒有響應udp

服務器:

char msg[100]=""; 
int conn_sock,n; 
struct sockaddr_in server_addr,client_addr; 
conn_sock=socket(AF_INET,SOCK_DGRAM,0); 

server_addr.sin_family=AF_INET; 
server_addr.sin_port=htons(1234); 
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 
err=bind(conn_sock, (struct sockaddr *)&server_addr,sizeof(server_addr)); 

n=recvfrom(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,(socklen_t *)&client_addr); 
n=sendto(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,sizeof(client_addr)); 

在recvfrom的n的值是字節數。但在SENDTO()N的值是-1

客戶:

char msg[100]; 
int conn_sock,n,err; 
struct sockaddr_in server_addr; 
conn_sock=socket(AF_INET,SOCK_DGRAM,0); 

server_addr.sin_family=AF_INET; 
server_addr.sin_port=htons(1234); 
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 

cin>>msg; 
n=sendto(conn_sock,msg,strlen(msg),0,(struct sockaddr *)&server_addr,sizeof(server_addr));  
n=recvfrom(conn_sock, msg, 15, 0, (struct sockaddr*) &server_addr,(socklen_t *)&server_addr); 

recvfrom的()不從服務器接收的任何數據。

回答

1

這兩條線都是錯誤的:

// In the server 
n=recvfrom(conn_sock,msg,sizeof(msg),0,(struct sockaddr *)&client_addr,(socklen_t *)&client_addr); 

// In the client 
n=recvfrom(conn_sock, msg, 15, 0, (struct sockaddr*) &server_addr,(socklen_t *)&server_addr); 

recvfrom()最後兩個參數都應該指向兩個獨立變量。其中一個接收對方的網絡地址,另一個接收該網絡地址的長度。您將同一個指針值傳遞給兩者意味着地址長度會覆蓋地址數據的前幾個字節,從而導致地址數據損壞並導致不良情況。

這裏的服務器應該如何工作的,接收長成一個獨立的變量:

struct sockaddr_storage client_addr; 
socklen_t client_addr_len = sizeof(client_addr); // This is an in+out parameter 
n=recvfrom(..., (struct sockaddr *)&client_addr, &client_addr_len); 
n=sendto(..., (struct sockaddr *)&client_addr, client_addr_len); 

請注意,我用了一個sockaddr_storage代替sockaddr_in。 A sockaddr_storage保證足夠大以容納支持的地址系列的任何有效套接字地址類型,以便該代碼將與IPv6向前兼容。

同樣,這裏的客戶端應該如何工作的:

n=sendto(..., &server_addr, sizeof(server_addr)); 
do 
{ 
    struct sockaddr_storage peer_addr; 
    socklen_t peer_addr_len = sizeof(peer_addr); 
    n=recvfrom(..., (struct sockaddr *)&peer_addr, &peer_addr_len); 
} while (!areSockAddrsEqual((struct sockaddr *)&server_addr, (struct sockaddr *)&peer_addr)); 

... 

bool areSockAddrsEqual(struct sockaddr *addr1, struct sockaddr *addr2) 
{ 
    if (addr1->sa_family != addr2->sa_family) 
     return false; 

    switch (addr1->sa_family) 
    { 
    case AF_INET: 
     struct sockaddr_in *addr1_in = (struct sockaddr_in *)addr1; 
     struct sockaddr_in *addr2_in = (struct sockaddr_in *)addr2; 
     return (addr1_in->sin_port == addr2_in->sin_port && 
       addr1_in->sin_addr.s_addr == addr2_in->sin_addr.s_addr); 
    ... 
    // Other address families such as AF_INET6 left as an exercise 
    } 
} 

在這裏,我們再次確認通過一個單獨的socklen_t指針接收地址長度,然後我還添加了一個循環,以確保實際我們收到的數據包是我們期望從預期服務器上得到的數據包。如果我們接收到一個不同的數據包(比如說,由於另一個同伴剛剛在錯誤的時間發送了一個數據包),我們忽略它。

檢查兩個套接字地址是否相等有點粗糙,因爲它取決於地址系列,並且支持IPv4和IPv6都很棘手。