【发布时间】:2015-01-18 14:49:46
【问题描述】:
我使用fpFork() 调用编写了一个多线程 tcp 服务器。工作正常,但在客户端断开连接后,僵尸进程仍然存在。有一个无限循环,我等待传入连接,fork,将此连接传递给孩子,孩子会处理它然后退出。但是,在父节点终止之前,子节点仍然是僵尸。
while True do
begin
// Accept connection
ClientAddrLen := sizeof(ClientAddr);
ClientSock := fpaccept(ServerSock, @ClientAddr, @ClientAddrLen);
if ClientSock > 0 then // Success?
begin
Pid := fpFork();
// Error fork
if pid < 0 then
begin
CloseSocket(ClientSock);
continue;
end
// Child process
else if pid = 0 then
begin
CloseSocket(ServerSock);
handleClient(ClientSock);
CloseSocket(ClientSock);
Halt(0);
end
// parent process
else if pid > 0 then
begin
CloseSocket(ClientSock);
continue;
end;
end;
end;
我对函数 fpWait() 或 fpWaitPid() 感兴趣,但免费的 pascal 文档缺少示例,谷歌搜索它毫无价值,因此我什至不知道如何使用它。
我在 FreeBSD 上使用 fpc 2.6.4。
更新 1 经过一些反复试验、阅读手册和讨论后,我尝试了一些组合。我将以下函数放在已执行代码的父部分中:
else if pid > 0 then
begin
CloseSocket(ClientSock);
//here
continue;
end;
a) 使用WaitProcess(pid)(等同于fpWaitPid(pid, @Status, 0))
使用此父进程等待子进程,但是由于父进程正在等待,它无法接受另一个连接,直到子进程终止。
b) 使用fpWaitPid(pid, @Status, WNOHANG)
这个函数不会阻塞程序,但它不会做任何事情。就像功能甚至不存在一样。这很令人困惑,因为在我读到的任何地方(它是用 C 编码的,但没关系,这些函数只是 unix 调用的包装器)都建议使用这个。
在这一点上,我不知道可能出了什么问题。提前谢谢你。
【问题讨论】:
-
所有这些 fp* 函数都是带有“fp”前缀的普通 unix 函数,以避免冲突(如读取、写入和打开).. fpwaitpid 是一个围绕等待循环的常见原因的包装器,来自理查德史蒂文斯iirc。
-
@MarcovandeVoort 好点,我做了一些反复试验,但似乎没有任何效果。我会在我的问题中解释它
-
我不是真正的分叉服务器专家(我更喜欢线程方法),但我会仔细检查你的场景是否匹配分叉服务器骨架,也许需要复制句柄或其他一些需要的额外处理。
-
@MarcovandeVoort Treads 可能是比这更好的解决方案,但我完全不熟悉 Pascal 中的线程。如果你能指出我正确的方向。
-
对于基于线程的套接字,逻辑方向是重用或至少看看一些现成的套接字套件。主要是 indy 和 synapse,在较小程度上是不可移植的 ICS(也存在于 Delphi 中)。
标签: fork pascal freepascal zombie-process