套接字对、perl、KEEPALIVE 和轮询

Posted

技术标签:

【中文标题】套接字对、perl、KEEPALIVE 和轮询【英文标题】:socket pairs, perl, KEEPALIVE, and polling 【发布时间】:2009-12-15 15:48:13 【问题描述】:

我已经开始在 linux 和 windows 上使用 socketpairs,以便在两个平台上捕获子进程的输出。我通过将 STD* 复制到套接字对中的一个套接字上来做到这一点(我在 perl 中使用 Win32::SocketPair 用于 Windows 上的套接字对)。我这样做的主要原因是读取不会阻塞输出文件句柄。

我遇到的问题是 kill(0,...) 在 Windows 上不起作用,所以我需要另一种方法来检测进程是否关闭。我查看了 SO_KEEPALIVE,但这似乎不适用于套接字对...我使用了 setsockopt(...) 然后 getsockopt(...) 并且在调用 setsockopt() 之前和之后 SO_KEEPALIVE 选项关闭。

然后我开始研究轮询套接字上的事件。 POLLHUP 事件看起来很有希望,但我不确定当它们像这样使用时它是否有效。

我正在寻找自动化交互式程序(不,我不能使用除非它在 ​​Windows 平台上不起作用......除非你找到一个可以做到的?)。我一直在 Windows 上使用“cat”进行测试(我安装了 cat.exe)。到目前为止看起来不错,但有两个问题:

无法检测进程是否死机(kill(0,...) 不起作用) 无法从子进程中检测到 EOF(sysread 似乎总是返回 undef 或读取的字节数,从不返回 0,即使在我关闭 ($sock, 1) 之后也是如此)

我可能在做一些非常愚蠢的事情,但我们将不胜感激任何建议/帮助。

更新:我开始使用 waitpid($pid, WNOHANG) 来检测“仍在运行”的情况,这很有帮助,因为在读取所有内容后进程似乎总是死亡。如果 pid 仍在运行,waitpid 返回 0。但是,它不是 EOF,总比没有好,但我仍在寻找其他输入。这显然并不理想。

UPDATE2:这个 Q/A 帮助解决了我的问题的 EOF 部分,并不完美,但更好: How epoll detect clientside close in Python?

【问题讨论】:

一般来说,套接字无法判断连接的另一端何时断开。这就是 TCP 的本质。出于这个原因,网络应用程序实现了心跳和关闭连接约定。 我想我认为这就是 KEEPALIVE 的用途,我弄错了吗? KEEPALIVE 是告诉服务器尝试保持连接打开,但服务器可能不想或无法尊重它。通常使用 KEEPALIVE,有一个约定是在消息中包含消息长度(如 HTTP/1.1 中的“Content-length”标头),因此接收者确切知道要读取多少字节。 【参考方案1】:

如果它在 WIN32 环境中受支持,并且您的进程正在生成子进程,您可以尝试设置一个信号处理程序以从父进程中生成的进程中捕获 SIGCHLD 信号...类似于:

$SIGCHLD = 子 print "caught sigchld from child process"; ;

这应该会告诉您其中一个子进程是否已退出。

【讨论】:

...我很确定信号通常是“unix-ism”。除非我遗漏了什么……我认为这在 Windows 平台上不起作用。但我想我可以试试…… 是的,没错,信号是 UNIX 的东西。问题是 Win32 Perl 是否使用 Windows 的 ITC 实现并通过 API(即 Perl 中的信号接口)模拟它们,或者它们是否提供完全独立的 API 来挂钩消息传递。 答案是否定的(除非您使用的是 Cygwin)。【参考方案2】:

在 Linux 中,您可以将套接字设置为非阻塞(至少从 5.8 开始):

 $socket->blocking(0);   # or (*SOCKET)->blocking(0);

这在 Windows 上不起作用(好吧,也许它在 5.10 中起作用),但您可以在尝试读取套接字之前使用 4-arg 选择调用来查看套接字上是否有输入(在 Windows 中, 4-arg select 仅适用于套接字句柄,不适用于文件句柄或管道)。

如果您仍需要判断 Windows 进程(具有已知 PID)是否处于活动状态,请检查 Win32::Process::Open method,它将尝试打开 Windows 进程的句柄并在失败时返回零。


编辑:我之前没有注意到你说套接字来自子进程。在这种情况下,您可以调用

waitpid $pid, WNOHANG;   # and    use POSIX ':sys_wait_h'

随时。当waitpid 没有返回-1 时,你就知道进程已经死了。

【讨论】:

我正在使用 select() 检查待处理的输入,但我的问题的核心是如何检测连接是否仍然存在。我也使用非阻塞 I/O,即使它在 Windows 中效果不佳……如果有的话。我将研究 Win32::Process::Open 方法。 我很确定我们的大脑是联系在一起的...我刚刚实现了这个...没有先查看您的编辑...它突然出现在我的脑海中。哈哈! 是的,我最近也在考虑 fork/socket 的东西。

以上是关于套接字对、perl、KEEPALIVE 和轮询的主要内容,如果未能解决你的问题,请参考以下文章

轮询和 Web 套接字中的连接

SO_KEEPALIVE 的 C 套接字编程

套接字,轮询,无套接字结果?

非阻塞套接字轮询与阻塞套接字

浅谈长连接keepalive和套接字重用reuse对高并发的影响

Opera 将长轮询套接字打开