1

我有一个主要编写的 PHP CLI 脚本,它用作聊天服务器以供聊天客户端连接(不要问我为什么要在 PHP 中这样做,那是另一个故事哈哈)。

我的脚本利用 socket_select() 函数挂起执行,直到套接字上发生某些事情,此时它唤醒,处理事件,并等待下一个事件。现在,我需要每 30 秒左右执行一些例行任务(检查是否应该解除临时禁止用户,保存用户数据库,其他各种事情)。

据我所知,PHP 根本没有很好的多线程支持。我的第一个想法是每次套接字生成事件并让程序再次流动时比较时间戳,但这非常不一致,因为服务器很可能会闲置几个小时而没有执行我的任何清理例程。

我遇到了 PHP pcntl 扩展,它让我可以使用为发送 SIGALRM 分配一个时间间隔,并在每次发送时执行一个函数。这似乎是我的问题的理想解决方案,但是 pcntl_alarm() 和 socket_select() 相互冲突非常糟糕。每次触发 SIGALRM 时,我的套接字控制代码都会发生各种疯狂的事情。

我的程序相当长,所以我不能在这里全部发布,但这没关系,因为我不相信我在代码方面做错了什么。我的问题是:有什么方法可以在与等待的 socket_select() 相同的线程中处理 SIGALRM?如果是这样,怎么做?如果没有,我的选择是什么?

这是我的程序的一些输出。我的警报功能只是输出“滴答声!” 每当它被调用时,就可以很容易地判断事情何时发生。这是允许它打勾 4 次后的输出(包括错误)(尽管它说了什么,但没有实际尝试连接到服务器):

[05-28-10 @ 20:01:05] 聊天服务器在 192.168.1.28 端口 4050 上启动

[05-28-10 @ 20:01:05] 从文件中加载了 2 个用户

PHP 通知:未定义的偏移量:0 in /home/danny/projects/PHPChatServ/ChatServ.php 第 112 行

PHP 警告:socket_select():无法选择 [4]:第 116 行 /home/danny/projects/PHPChatServ/ChatServ.php 中的系统调用中断

[05-28-10 @ 20:01:15] 打勾!

PHP 警告:socket_accept():无法接受传入连接 [4]:第 126 行 /home/danny/projects/PHPChatServ/ChatServ.php 中的系统调用中断

[05-28-10 @ 20:01:25] 打勾!PHP 警告:socket_getpeername() 期望参数 1 是资源,布尔值在第 129 行的 /home/danny/projects/PHPChatServ/ChatServ.php 中给出

[05-28-10 @ 20:01:25] 接受来自 PHP 的套接字连接 注意:未定义的偏移量:第 112 行 /home/danny/projects/PHPChatServ/ChatServ.php 中的 1

PHP 警告:socket_select():无法选择 [4]:第 116 行 /home/danny/projects/PHPChatServ/ChatServ.php 中的系统调用中断

[05-28-10 @ 20:01:35] 打勾!

PHP 警告:socket_accept():无法接受传入连接 [4]:第 126 行 /home/danny/projects/PHPChatServ/ChatServ.php 中的系统调用中断

[05-28-10 @ 20:01:45] 打勾!

PHP 警告:socket_getpeername() 期望参数 1 是资源,布尔值在第 129 行的 /home/danny/projects/PHPChatServ/ChatServ.php 中给出

[05-28-10 @ 20:01:45] 接受来自的套接字连接

PHP 通知:未定义的偏移量:/home/danny/projects/PHPChatServ/ChatServ.php 第 112 行中的 2

4

1 回答 1

2

pcntl_alarm并且socket_select可以共存,但你需要知道如何正确地做到这一点。

特别是,如果警报在socket_select()等待时响起,则在处理警报后,socket_select()将立即返回并显示错误指示。错误是“中断的系统调用”,这是您在输出中看到的。您需要专门检查该错误,然后重试socket_select().

或者,您可以忘记使用警报,而使用socket_select(). 这就是tv_sec参数的用途 - 它以秒为单位给出超时,之后socket_select()即使没有套接字准备好也会返回。然后,您可以进行常规处理。

于 2010-05-30T10:01:40.113 回答