C++ 简单fork()程序
我正在尝试制作一个程序,用fork检查steam服务器的列表。我看到,如果我经常在服务器上安装10万条线路,程序就会以有线循环的方式运行,并且一遍又一遍地检查相同的服务器。调试之后,我发现即使是打印服务器ip的简单程序也出人意料 节目:C++ 简单fork()程序,c++,fork,C++,Fork,我正在尝试制作一个程序,用fork检查steam服务器的列表。我看到,如果我经常在服务器上安装10万条线路,程序就会以有线循环的方式运行,并且一遍又一遍地检查相同的服务器。调试之后,我发现即使是打印服务器ip的简单程序也出人意料 节目: #include <iostream> #include <sys/wait.h> #include <stdio.h> #include <cstring> #include <unistd.h> #
#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)代码>。否则,您会多次执行退出处理程序,这会对共享文件描述符等产生不可预测的影响。您在这里遇到了几个问题:
- 您不检查
的结果。这是目前为止最严重的问题,因为您正在使用100000个叉子。如手册页面所示,fork(2)
在子进程中返回fork()
,在父进程中返回子进程的pid,如果0
执行正确。但是在您的情况下,fork()
很快会给您一个错误,因为您可能无法在系统中同时启动100000个进程fork()
在出现错误时返回fork()
,您不需要检查它,因此一旦它无法生成新进程,您将在-1
命令的if
部分结束,将父进程中的错误视为成功的命令fork。这很可能导致一些不好的事情else
- 正如您在问题的另一个答案中所被告知的那样,如果您尝试调用
,而不是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
)取代了(由于新语言中新的面向对象功能,我事先表示歉意,并不是说Stroustrup比Kernighan或Ritchie好),所以,在C++中使用C I/O是强烈反对的。iostream
您将从所有这些评论中看到,您的解决方案与调用
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);
}