通过TCP客户端套接字接收数据的问题

时间:2008-11-26 02:24:09

标签: c sockets tcp

我正在尝试在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 个答案:

答案 0 :(得分:4)

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

值得检查的是,您没有收到错误 - 因此会使您的缓冲区下溢。

[注意:从此开始是Pax的工作 - 谢谢,我已将其转换为社区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时回来的,然后输入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>

你应该看到类似的东西。

答案 1 :(得分:2)

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

This section特别是客户端的代码完全符合您的要求。

答案 2 :(得分:0)

编辑:下面的答案基于对问题的误解 - 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);

答案 3 :(得分: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 */ }
      }
    }
  }
}