2008-11-26 177 views
2

我想在C客戶端啓動,連接到服務器的地方製作一個TCP客戶端程序。然後它會發送一些信息,然後只聽收到的信息並作出相應的反應。通過TCP客戶端套接字接收數據的問題

我遇到麻煩的部分是持續聆聽。以下是我有

... 

while (1) { 
    numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0); 
    buf[numbytes] = '\0'; 
    printf("Received: %s\n", buf); 
    // more code to react goes here 
} 

... 

一旦連接到服務器,發送數據的兩條線後,服務器應收到的信息的好一點,但是當我運行它,它打印:

Received:

然後繼續坐在那裏,直到我強迫它關閉。

**編輯**時我做喬納森告訴我做,我得到如下:

Count: -1, Error: 111, Received:

因此,這意味着它的示數,但我該怎麼辦呢?

+0

客戶端是否關閉連接? – 2008-11-26 02:25:33

+0

嘗試打印strerror(errno)並查看錯誤是什麼 – Claudiu 2008-11-26 14:57:04

+0

您應該在清零緩衝區之前檢查numbytes> = 0,否則下溢可能使事情變得更加混亂。 – Hasturkun 2008-11-26 15:34:35

回答

4

打印出接收到的字節數 - 可能爲零,但請確認。

這將是值得檢查,你沒有得到一個錯誤 - 並因此下流你的緩衝區。

[注:從這裏開始是和平的工作 - 謝謝,我已經將它轉化爲社區維基所以我沒有得到代表處點不應有的。]

以下代碼將執行此操作。嘗試一下並請回報結果。

while (1) { 
    numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0); 
    buf[numbytes] = '\0'; 
    printf("Count: %d, Error: %d, Received: %s\n", numbytes, errno, buf); 
    // more code to react goes here 
} 

問題編輯後:

錯誤編號111 ECONNREFUSED - 這是不適合的recv()通常的錯誤代碼,但更適合於開放型呼叫(開放(),連接( )等)。

在任何情況下,ECONNREFUSED都是服務器端的問題,而不是客戶端 - 服務器故意拒絕接受您的傳入連接,因此您需要調查鏈接的結尾。

爲了測試這一點,改變你的代碼,以便它連接到www.microsoft.com端口80,然後發送一對夫婦任何舊的垃圾線。您應該從Web服務器返回一個錯誤消息,指出格式錯誤的HTTP請求。這將證明你的客戶端沒有問題。

這就是我回來的時候我telnet www.microsoft.com 80和類型hello其次ENTER兩次:

HTTP/1.1 400 Bad Request 
Content-Type: text/html; charset=us-ascii 
Server: Microsoft-HTTPAPI/2.0 
Date: Thu, 27 Nov 2008 01:45:09 GMT 
Connection: close 
Content-Length: 326 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd"> 
<HTML><HEAD><TITLE>Bad Request</TITLE> 
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD> 
<BODY><h2>Bad Request - Invalid Verb</h2> 
<hr><p>HTTP Error 400. The request verb is invalid.</p> 
</BODY></HTML> 

你應該會看到類似的東西。

0

編輯:下面是基於問題的誤解了答案 - 在OP的代碼實際上是嘗試的recv()上的一個插口,它的open()版到遠程服務器。下面的東西留給後人。


請顯示更多代碼。

一些意見雖然:

  • 是插座listen()ing
  • 你有沒有accept()ed傳入連接
  • 在TCP套接字上使用recv()稍有不同。改爲使用read()
  • 使用strerror()將111錯誤代碼轉換爲本地錯誤字符串 - 每個UNIX O/S可以有自己的從數字映射到Exxx錯誤代碼的映射,因此我們無法確定您的系統上出現了什麼錯誤。

正常代碼迴路(對於單線程非分叉應用程序)的樣子:

s = socket(); 
err = listen(s, n); // n = backlog number 
while (1) { 
    int fd = accept(s, &addr, sizeof(addr)); 
    while (1) { 
     int numrecv = read(fd, ...); 
     // break if eof 
    } 
    close(fd); 
} 
close(s); 
0

什麼用無限循環的?爲什麼不使用select(),以便只有在有實際數據要讀取時才調用recv()?

在以前的生活中,我爲MUD編寫了網絡代碼,而且我仍然可以在我的腦海中編寫輪詢循環。 ROM 2.3中的循環是這樣的(從內存中,所以如果宏參數的順序錯誤,請原諒我):

#define MAX_CONNECTIONS 256 
int main(int argc, char *argv[]) 
{ 
    int i = 0; 
    int running = 1; 
    int connections[MAX_CONNECTIONS]; 
    while(running) 
    { 
    fd_set in_fd, out_fd, exc_fd; 
    FD_ZERO(in_fd); 
    FD_ZERO(out_fd); 
    FD_ZERO(exc_fd); 
    for(i = 0; i < MAX_CONNECTIONS; i++) 
    { 
     if(connections[i] > 0) 
     { 
     FD_SET(&in_fd, connections[i]); 
     FD_SET(&out_fd, connections[i]); 
     FD_SET(&exc_fd, connections[i]); 
     } 
    } 
    select(&in_fd, &out_fd, &exc_fd, NULL); // this will block until there's an I/O to handle. 
    for(i = 0; i < MAX_CONNECTIONS; i++) 
    { 
     if(FD_ISSET(&exc_fd, connections[i])) 
     { /* error occurred on this connection; clean up and set connection[i] to 0 */ } 
     else 
     { 
     if(FD_ISSET(&in_fd, connections[i])) 
     { /* handle input */ } 
     if(FD_ISSET(&out_fd, connections[i])) 
     { /* handle output */ } 
     } 
    } 
    } 
} 
相關問題