2008-11-26 181 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 */ } 
     } 
    } 
    } 
} 
相关问题