2011-11-13 46 views
0

我目前有一個問題在服務器和客戶端之間傳遞消息。 據我所知,我正確遵循了Beej's Socket Programming Tutorial概述的套接字編程的最佳實踐。C++套接字recv()系統調用返回-1

當我運行這兩個進程時,recv()系統調用返回-1(錯誤),而不是接收的字節數。當試圖輸出buf時,還有一堆gobbledygook角色。這是有道理的,因爲錯誤。

我想知道是否有人可以引導我在正確的方向,爲什麼我有問題與recv()?以下是相關的代碼片段。

服務器:

struct sockaddr_storage their_addr; 
socklen_t addr_size; 
int sockfd, newfd, byte_count, status; 
char buf[512]; 
struct addrinfo hints, *res; 

// first, load up address structs with getaddrinfo(): 
memset(&hints, 0, sizeof hints); 
hints.ai_family = PF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 

// get address info, print stuff if error 
if((status = getaddrinfo("nunki.usc.edu", "21957", &hints, &res)) !=0){ 
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); 
    exit(1); 
} 

// make a socket: 
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){ 
    cout << "socket fail" << endl; 
} 

// bind the socket to the port 
bind(sockfd, res->ai_addr, res->ai_addrlen); 

// required output 
cout << "Phase1: Login server has TCP port number " << "21957 " 
    << "and IP address " << getIPfromHost("nunki.usc.edu") << endl; 

// listen for incoming connections 
listen(sockfd, 10); 
cout << "after listen" << endl; 

// halt until receipt 
addr_size = sizeof(their_addr); 
newfd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size); 
cout << "after accept" << endl; 

// Now that we're connected, we can receive some data 
byte_count = recv(sockfd, buf, sizeof buf, 0); 
printf("recv()'d %d bytes of data in buf\n", byte_count); 
printf("Msg is %s\n", buf); 

客戶:

struct addrinfo hints, *res; 
int sockfd; 

// first, load up address structs with getaddrinfo(): 
memset(&hints, 0, sizeof hints); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
getaddrinfo("nunki.usc.edu", "21957", &hints, &res); 

// make a socket: 
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){ 
    cout << "socket fail" << endl; 
} 

// attempt connection to port 
if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1){ 
    cout << "connect fail" << endl; 
} 

// send message to server 
cout << "sockfd " << sockfd << endl; 
int byte_count = send(sockfd, "Hello", 5, 0); 
cout << byte_count << endl; 

以下是服務器輸出:

Phase1: Login server has TCP port number 21957 and IP address 68.181.201.3 
after listen 
after accept 
recv()'d -1 bytes of data in buf 
Msg is ÿhÿ?sÈ 
Glæ 

以下是客戶機的輸出:

sockfd 4 
5 

回答

6

您在錯誤的插座上致電recv。你需要recvnewfd

byte_count = recv(newfd, buf, sizeof buf, 0); /* newfd instead of sockfd. */ 

現在,這就是出路,

據我所知,我是正確遵循了插座 最佳實踐編程

我完全不同意。

  • 你是不是檢查返回狀態爲listenbindgetaddrinfo
  • 有沒有在你的程序strerrorperror
+0

非常感謝。我對這個疏忽感到驚訝。另外,我將添加返回狀態和錯誤輸出。我承認有點懶。 – aaronmar

+0

+1對_you不檢查退貨狀態_ – ninjalj

2

你想用從接受返回套接字的recv()()

byte_count = recv(newfd, buf, sizeof buf, 0); 
+0

謝謝!今晚快速響應.. sheesh – aaronmar

0

也許我不應該寫這個作爲一個答案,但作爲一個評論。儘管如此,恕我直言,你使用getaddrinfo()似乎是錯的。

  • 在客戶端,它應該被調用,然後遍歷結果直到可以建立連接。

    所以

    struct addrinfo * r2 
    sockfd = -1; 
    for (r2=res; r2; r2=r2->ai_next) { 
        // make a socket: 
        if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){ 
         continue; // next result 
        } 
    
        // attempt connection to port 
        if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1){ 
         close(sockfd); 
         sockfd = -1; 
         continue; 
        } 
    } 
    if (sockfd == -1) { 
        // do error handling 
    } 
    

    通過這種方式,你可以檢查所有可能的連接。

  • 在服務器端,使用getaddrinfo()比較少見。通常情況下,您將創建一個IPv6套接字並使其能夠監聽IPv4,並使用setsockopt()取消設置IPV6_V6ONLY標誌。通過這種方式,套接字可以同時監聽IPv6和IPv4。 (唉,不能在Windows XP AFAIK)

+1

調用getaddrinfo服務器端沒有任何問題,它仍然是一個方便的API。 'AI_PASSIVE'應該已經設置好了。 –

+0

謝謝!這對我來說是全新的,所以我[對此有疑問](http://stackoverflow.com/questions/8113805/usage-of-ai-passive)... – glglgl

0

sockfd只是useed聽客戶,newfd用於數據傳輸。