【问题标题】:Problems receiving data over a TCP client socket通过 TCP 客户端套接字接收数据的问题
【发布时间】:2010-09-24 02:10:45
【问题描述】:

我正在尝试在 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,已接收:

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

【问题讨论】:

  • 客户端是否关闭连接?
  • 尝试打印 strerror(errno) 看看是什么错误
  • 在将缓冲区归零之前,您应该检查 numbytes >=0,下溢可能会使事情变得更加混乱。
  • 嗨,Anti9,您发现问题所在了吗?好奇的人想知道。

标签: c sockets tcp


【解决方案1】:

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

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

[注意:从这里开始是 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-type 调用(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>

你应该会看到类似的东西。

【讨论】:

  • 当recv返回0时表示socket已被远程主机关闭,所以可能不是0。可能是-1,表示错误,错误可能是EWOULDBLOCK或EAGAIN表示非阻塞读取失败,因为没有数据要接收。
  • 不客气,@JL,我宁愿修改一个半体面的答案也不愿试图捏造代表,尤其是当你的回答是正确的时候——在那之后我所做的就是充实一些选项要调查的提问者。
【解决方案2】:

我强烈推荐Beej's Guide to Network Programming

This section 特别有代码,可以满足您的要求。

【讨论】:

  • 这是我获得代码的地方,据我所知,它实际上并没有循环接收操作。只收到一次。
【解决方案3】:

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


请显示更多您的代码。

不过有一些观察:

  • 是套接字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);

【讨论】:

  • 为什么在套接字上使用 recv 是不寻常的?
  • 好的,有点不寻常。除非您需要特定于套接字的标志,否则我更喜欢使用普通的“读取”函数,以便可以使用任何类型的文件描述符。
  • 我没有尝试监听传入连接。这是一个客户。
  • 啊 - 好的 - 误解了消息流。在这种情况下,您的 111 可能是 ECONNREFUSED,这意味着另一端不接受连接。检查你的 connect() 系统调用的结果。
【解决方案4】:

无限循环是怎么回事?为什么不使用 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 */ }
      }
    }
  }
}

【讨论】:

    猜你喜欢
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多