3

我正在尝试在 C 中创建一个 TCP 客户端程序,客户端将在其中启动,连接到服务器。然后它会发送一些信息,然后只听它接收到的内容并做出相应的反应。

我遇到问题的部分是持续聆听。这是我所拥有的

...

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

...

连接到服务器后,发送两行数据后,服务器应该会收到很多信息,但是当我运行它时,它会打印:

已收到:

然后继续坐在那里,直到我强迫它关闭。

** 编辑 ** 当我按照乔纳森告诉我的操作时,我得到以下信息:

计数:-1,错误:111,接收:

所以这意味着它的错误,但我该怎么办呢?

4

4 回答 4

4

打印出接收到的字节数 - 它可能为零,但请确认。

值得检查您没有收到错误 - 因此导致缓冲区下溢。

[注意:从这里开始是 Pax 的工作-谢谢,我已将其转换为 Community Wiki,因此我不会获得不应有的代表点数。]

以下代码将执行此操作。请尝试并报告结果。

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() 的常见错误代码,但更适合开放式调用(open()、connect() 等)。

无论如何,ECONNREFUSED 是服务器端的问题,而不是客户端的问题 - 服务器故意拒绝接受您的传入连接,因此您需要调查链接的那一端。

为了对此进行测试,请更改您的代码,使其在端口 80 上连接到 www.microsoft.com,然后发送几行任何旧垃圾。您应该从他们的 Web 服务器返回一个错误,指示格式错误的 HTTP 请求。这将证明您的客户端没有问题。

这是我在输入后返回的内容,然后telnet www.microsoft.com 80输入两次:helloENTER

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>

你应该看到类似的东西。

于 2008-11-26T02:26:47.493 回答
2

我强烈推荐Beej 的网络编程指南

本节特别提供了完全按照您的要求执行的客户端代码。

于 2008-11-26T02:43:55.340 回答
0

编辑:下面的答案是基于对问题的误解 - OP 的代码实际上是在尝试在它打开()到远程服务器的套接字上进行 recv()。左下方的东西供后代使用。


请显示更多您的代码。

不过有一些观察:

  • 是插座listen()ing吗?
  • accept()ed有传入的连接吗
  • recv()在 TCP 套接字上使用有点不寻常。改为使用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);
于 2008-11-26T14:27:11.753 回答
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 */ }
      }
    }
  }
}
于 2008-11-27T05:43:04.633 回答