【问题标题】:How do open child sockets get closed?打开的子套接字如何关闭?
【发布时间】:2016-02-14 20:53:49
【问题描述】:

我在 while(1) 循环中生成了一个子进程,它似乎接受正在进行的 TCP 连接。我正在寻找套接字子进程的“正常”行为的确认,假设父进程没有死(我发现了很多关于如何在父进程死时杀死子进程的建议......)。

void 
dostuff (int sock, int* count)
{
  while(1){
    *count = *count +1;

    char cnt[20];
    sprintf(cnt, "count: %d\n", *count);

    int n;
    char buffer[bufsize];       
    bzero(buffer,bufsize);

    n = read(sock,buffer,bufsize);
    if (n < 0) error("ERROR reading from socket");
    fprintf(stderr,"From the client:\n%s",buffer);

    char reply[bufsize];
    bzero(reply, bufsize);
    strcat(reply, cnt);

    n = write(sock, reply, bufsize);
    if (n < 0) error("ERROR writing to socket");
  }
}

我怀疑子进程的 TCP 会话结束后会自动关闭,这是正确的吗?

它在重新连接到当前 TCP 会话时出现,实际上子进程从 while 循环的顶部开始,在读取和写入之前递增计数。我可以依靠这种行为吗?还是让它可靠?

【问题讨论】:

  • fprintf(stderr,"From the client:\n%s",buffer); 不好:read 不要添加尾随 '\0' 所以buffer 不是可打印的字符串(以这种方式)。
  • 但是为什么孩子会跳出这个循环呢?你永远不会退出/返回/中断它(或者可能在 error() 函数中,但它的内容没有显示。
  • 缓冲区在这种情况下在写入之前填充了“\0”。
  • 如果你得到准确(或更多)buffsize 数据怎么办(注意:“更多”意味着你将得到准确的 buffsize 数据,当然)?不管你的主要问题是什么,这段代码中没有任何内容让我们假设循环将结束。
  • 如果n 为零,您应该关闭套接字并退出循环。如果n 是负数,您应该记录错误,关闭套接字,然后退出循环。在这两种情况下,您都不应继续,就好像您已收到数据一样。如果n 是正数,则应将其视为实际读取的字节数。不对尾随空值做任何假设。

标签: c sockets


【解决方案1】:

所以第一个编码问题:fprintf(stderr,"From the client:\n%s",buffer);。即使buffer 以零初始化,您也可能会得到bufsize 字节,因此fprintf 将在缓冲区结束后读取数据。而且您处于一个循环中,因此每次读取都可以提供不同的大小,因此您可以从以前的缓冲区内容中打印“垃圾”。 您应该使用需要编写多个字符的函数(即fwrite)。

另一点更多的是“风格”问题:您从读取中得到n 字节,那么为什么要写回bufsize 字节而不是n?唯一的好处是拥有“恒定大小”的消息。

对于内部循环,其中的任何函数都不能离开此循环、函数或程序。 您必须根据需要明确退出循环(使用break)或函数(使用return)甚至程序(使用exit)。

在其当前状态下,函数从套接字读取。然后它会打印一条错误消息但继续其工作(由您决定在发生读取错误时该怎么做)。在它打印消息(可能是前一个,因为你没有清理内容)并写入套接字之后,这将失败(如果套接字关闭,你就无法读取,你无法写入)。

所以这里的重点是:尝试从/向关闭的套接字读取/写入只会从 read/write 函数返回 -1。之后要做什么由您决定。

函数应该如下所示:

void dostuff (int sock, int* count) {
  while(1){
    int n;
    *count = *count + 1;
    char buffer[bufsize];
    n = read(sock,buffer,bufsize);
    if (n <= 0) {
      error("ERROR reading from socket (or EOF)");
      close(sock); // close our side whatever
      break;  // leave the loop (or return)
    }
    fprintf(stderr,"From the client:\n");
    fwrite(buffer, 1, n, stderr); // write the n elements
    char reply[bufsize];
    reply[0] = '\0';  // no need to clear all buffer
    strcat(reply, cnt);
    n = write(sock, reply, n);  // just write N elements
    if (n < 0) {
      error("ERROR writing to socket");
      close(sock); // close our side whatever
      break; // not able to write -> problem
    }
  }
}

【讨论】:

  • error(),不管它是什么,如果不将n 传递给它,是否会知道是否打印errno 等?为什么要在流的末尾调用一个名为 error() 的函数,这不是错误?您不应该在同一块中处理 n == -1n == 0。你需要两个测试。
  • @EJP:这是 OP 的功能。我没有改变它。任何函数都可以访问errno,直到您之前不执行其他系统调用。是的,-1 和 0 应该分开。
  • @hexasoft 我很高兴得到实际帮助,这与确认读取功能阻塞直到套接字有要读取的消息并且如果 TCP 连接关闭它将失败有关。剩下的就是教我吃鸡蛋并对所涉及的代码做出全面的假设。例如,您认为 error() 函数的作用是什么…… Google DRY。无论如何,这与问题无关。假设您选择将您的答案限制在所提问题的范围内,我仍然很高兴承认实际帮助。
猜你喜欢
  • 2013-10-19
  • 2017-12-24
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
  • 2014-02-15
  • 2014-09-18
  • 2011-08-18
  • 1970-01-01
相关资源
最近更新 更多