C++ 简单fork()程序

C++ 简单fork()程序,c++,fork,C++,Fork,我正在尝试制作一个程序,用fork检查steam服务器的列表。我看到,如果我经常在服务器上安装10万条线路,程序就会以有线循环的方式运行,并且一遍又一遍地检查相同的服务器。调试之后,我发现即使是打印服务器ip的简单程序也出人意料 节目: #include <iostream> #include <sys/wait.h> #include <stdio.h> #include <cstring> #include <unistd.h> #

我正在尝试制作一个程序,用fork检查steam服务器的列表。我看到,如果我经常在服务器上安装10万条线路,程序就会以有线循环的方式运行,并且一遍又一遍地检查相同的服务器。调试之后,我发现即使是打印服务器ip的简单程序也出人意料

节目:

#include <iostream>
#include <sys/wait.h>
#include <stdio.h>
#include <cstring>
#include <unistd.h>
#include <string>

#include <ctype.h>
#include <stdlib.h>
#include <fstream>

#include <sstream>
#include <algorithm>
#include <iterator>
#include <regex>
#include <vector>

int main(int argc, char **argv)
{
    puts("Beginning program");

    int max_forks = 500;
    int num_forks = 0;

    FILE *fpxxx = fopen("servers", "r");
    if(fpxxx == NULL) {
        perror("Unable to open file!");
        exit(0);
    }

    char chunk[128];

    while(fgets(chunk, sizeof(chunk), fpxxx) != NULL)
    {
        // puts(chunk); // same result if put the line here

        if(!(fork()))
        {
            // sleep(3);
            puts(chunk);

            exit(0);
        }
        else
        {
            num_forks++;

            if (num_forks >= max_forks)
            {
                wait(NULL);
                num_forks--;
            }
        }
    }

    fclose(fpxxx);
    sleep(10);
}
Beginning forking
94.xxx.xxx.209

Beginning forking
184.xxx.xxx.117

Beginning forking
108.xxx.xxx.86

Beginning forking
178.xxx.xxx.140

Beginning forking
113.xxx.xxx.132

Beginning forking
45.xxx.xxx.16

... (many lines, thus servers.txt has 100.000+ ips)

# after a while i see
Beginning forking
178.xxx.xxx.140
# again and again and again


# sometimes i even see
Beginning forking
37.247.104.933.17.199.143
预期产出:

94.xxx.xxx.209
184.xxx.xxx.117
108.xxx.xxx.86
178.xxx.xxx.140
113.xxx.xxx.132
45.xxx.xxx.16
我忘了什么吗?堆似乎已损坏。为什么我看到
开始分叉
,好像程序从一开始就再次运行?我知道fork正在生成另一个进程,但我认为
fork()
会从
fork()
所在的位置派生程序

多谢各位

编辑:解决方案是


这应该是退出(0)。否则,您会多次执行退出处理程序,这会对共享文件描述符等产生不可预测的影响。

您在这里遇到了几个问题:

  • 您不检查
    fork(2)
    的结果。这是目前为止最严重的问题,因为您正在使用100000个叉子。如手册页面所示,
    fork()
    在子进程中返回
    0
    ,在父进程中返回子进程的pid,如果
    fork()
    执行正确。
    但是在您的情况下,
    fork()
    很快会给您一个错误,因为您可能无法在系统中同时启动100000个进程
    fork()
    在出现错误时返回
    -1
    ,您不需要检查它,因此一旦它无法生成新进程,您将在
    if
    命令的
    else
    部分结束,将父进程中的错误视为成功的命令fork。这很可能导致一些不好的事情
  • 正如您在问题的另一个答案中所被告知的那样,如果您尝试调用
    exit(3)
    ,而不是
    \u exit(2)
    ,您将收到大量重复输出(缓冲区内容),因为
    atexit()
    功能使其在父级和子级中刷新
    stdio
    缓冲区。在终端输出上,这种情况不会发生(您不会看到这种情况),因为
    stdio
    stdout
    上对终端使用行缓冲,所以它会在
    fork()
    之前刷新缓冲区。但仅当输出设备是终端时,而不是文件时(缓冲区仅在缓冲区已满时或退出时刷新,然后刷新所有未刷新的
    stdio
    缓冲区)。由于我假设您正在搜索某个文件,我假设您已将输出重定向到某个文件,因此会出现大量重复输出
  • 另外,不要在结束时调用
    sleep(10)
    来等待子进程完成,而是使用一个循环,
    wait(2)
    等待子进程终止,直到您从
    wait
    中得到一个错误。这意味着你不会有更多的孩子活着
  • 这是最重要的。所有系统调用都记录在联机手册页面中。请使用它们,因为我所解释的都在这里
  • 小问题。C++中使用旧的C库调用来执行I/O(<代码> PUT/<代码>)。尽量避开它们。C++是设计用来使用所有C语言调用的,所以很多遗留软件是可重用的,并且在C++中工作。对于许多遗留库来说,这是正确的,但是
    stdio
    在很久以前就被设计得更好的库(
    iostream
    )取代了(由于新语言中新的面向对象功能,我事先表示歉意,并不是说Stroustrup比Kernighan或Ritchie好),所以,在C++中使用C I/O是强烈反对的。

您将从所有这些评论中看到,您的解决方案与调用
getline()
的方式不同,因为您的代码中存在严重的问题。

您的进程被分叉了100000次???这是。。。错…你的操作系统能处理100000个进程吗?在一个程序中。进程很重,请使用线程,尽管您无论如何不能使用那么多。创建一些队列,以便在其中一个挂起时不会影响其他线程。也许你真的习惯于做一些完全不同的事情,你没有告诉我你想用叉子解决什么问题线程的限制是什么?我正在尝试快速检查一些服务器,这就是我使用forks的原因。我在线程之前使用过,如果我在线程中做了一些错误的事情,弄乱了整个程序的堆,
fork()
有点友好。您是否知道在
fork()
之后,每个进程都有自己的
num\u forks
(以及其他所有变量)副本,并且在其中一个进程中所做的更改在其他进程中看不到?您可以尝试将要共享的变量放入DLL的
共享
数据部分,或者使用共享内存或任何其他IPC机制。如果使用共享内存或共享DLL节,请确保使用
InterlockedIncrement
InterlockedIncrement
来更改变量。谢谢您的提示,有没有您推荐的示例?我在PHP中也做了同样的事情,效果很好。我看到过同样的错误导致了一个可怕的错误,令人难以置信的严重安全违规。我无法透露我必须向谁解释,但我们只能说这是我一生中最不愉快的谈话之一。@DavidSchwartz,你不会多次处决atexit handler。您将在每个进程上执行一次。这会产生多次写入缓冲输出的副作用,因为文件描述符是
dup(2)
ed并共享文件指针。这可能就是正在发生的事情,因为他已经将输出重定向到一个文件(因为他有100000个输入行),他确实必须这样做,但这不是他唯一的错误。@LuisColorado如果进程
    if(!(fork()))
    {
        // sleep(3);
        puts(chunk);

        exit(0);
    }