将套接字资源转换为流套接字

Posted

技术标签:

【中文标题】将套接字资源转换为流套接字【英文标题】:Converting a socket resource into a stream socket 【发布时间】:2012-08-27 18:43:43 【问题描述】:

php 有两种不同的 API 用于与套接字交互。有基本包装了 C 套接字 API 的低级套接字 API。还有高级流套接字 API,它实现了 PHP 流接口。

很遗憾,流套接字 API 不支持设置低级套接字选项。然而,这是我必须做的事情。同样,套接字 API 不支持使用标准函数调用,如 freadfwritefclose,使其与我的其余代码不兼容。

PHP 5.4 引入了socket_import_stream 函数。这允许您获取流套接字并获取底层套接字资源。我的计划是使用它来创建流套接字,获取套接字,在其上设置一些选项,然后继续使用原始流套接字。

这对我不起作用的原因是我需要在绑定之前设置选项。绑定流套接字的唯一方法是使用stream_socket_server,它已经执行了绑定。这就是我无法使用它的原因。

我现在正在寻找socket_import_stream 的倒数,以便我可以将我的套接字资源转换为流套接字。我一直没能找到这样的功能,但我希望一些非常聪明的人可以帮助我。或者向执行它的 PHP 源提交一个补丁。或者给我一些关于编写这样一个补丁的提示。

编辑:我有一些代码作用于 PHP 流以从中解析 DNS 数据包。我想通过启用多播的套接字重新使用该代码。我无法在流套接字上启用多播,也不能在原始套接字上使用流函数。

EDIT2:我想将此流与stream_select 一起使用,因此很遗憾,不能选择自定义流包装器。

【问题讨论】:

来自 PHP 源代码的评论:hold a zval reference to the stream (holding a php_stream* directly could also be done, but this might be slightly better if in the future we want to provide a socket_export_stream) bitbucket.org/php/php-src/src/0ef8b095ccda/ext/sockets/… 所以我猜socket_export_stream 是你正在寻找的函数,不幸的是它看起来还没有实现。 您只是展示了您在为未描述的问题实施“解决方案”时遇到的问题。把原来的问题也摆出来,也许还有其他办法。 @Tiberiu-IonuțStan 我添加了一些关于我的问题的更多信息。 @igorw 不是从流中导入/导出套接字句柄,您如何看待扩展套接字流上下文以获取选项数组?在我看来,这将导致代码更简洁。 【参考方案1】:

这对我不起作用的原因是我需要在绑定之前设置选项。绑定流套接字的唯一方法是使用已执行绑定的 stream_socket_server。这就是我无法使用它的原因。

stream_socket_server()的第4个参数是$flags,默认为STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,所以不要省略,给0(或其他标志)。

所有设置完成后,您仍然可以使用socket_bind()socket_listen() 手动绑定(和监听)该套接字。

我没有尝试,只是一个想法。

【讨论】:

@Leigh 不正确,请注意您链接的第二行中的 == 0 @igorw 你是对的,出于某种原因,我认为它实际上是在做& ~STREAM_XPORT_SERVER 来检索原始标志,并根据STREAM_XPORT_CLIENT 的定义将其与 0 进行检查。所以确实,标志为 0 将跳过绑定/侦听部分。 这是个好主意,但不幸的是socket_import_stream 尝试获取套接字系列,在创建没有标志的服务器时该系列不存在。我收到“警告:socket_import_stream():无法获取套接字系列 [9]:错误的文件描述符”。【参考方案2】:

您可以将stream_wrapper_register 函数与实现streamWrapper 模板的类结合使用来创建多播套接字流。这将允许您利用所有内置的流函数,尽管它不如 socket_export_stream 方便。

【讨论】:

这是正确的解决方案。由于您可以使用套接字做很多事情,因此实现包装器应该是微不足道的。 这有点帮助,但是这个解决方案有一个问题。自定义流不能与stream_select 一起使用,因为无法提取文件描述符。现在将其添加到问题中。 我们可以使用像php://fd/N这样的文件描述符的直接访问来确定当前是我们的吗? @Alexander You can get file descriptors for each stream,在创建每个流时,您需要了解它们,但这可以通过一些工作来实现。 自定义流可以与 [php.net/manual/en/streamwrapper.stream-cast.php]streamWrapper::stream_cast 函数的黑魔法一起使用

以上是关于将套接字资源转换为流套接字的主要内容,如果未能解决你的问题,请参考以下文章

Javamail 无法将套接字转换为 TLS GMail

将 uint16_t 转换为 char[2] 以通过套接字(unix)发送

套接字编程 connect() 函数错误——“无法将 'main(int, char**)::sockaddr* 转换为 'const sockaddr”

在 NODeJS 中的 TCP 套接字上将十六进制字节转换为十进制

无法使用 SMTP 发送电子邮件(获取 javax.mail.MessagingException:无法将套接字转换为 TLS;)

UDP和套接字,recvfrom()返回-1,资源暂时不可用