【问题标题】:Get all contents of stream socket with fgets() in blocking mode在阻塞模式下使用 fgets() 获取流套接字的所有内容
【发布时间】:2017-05-07 08:07:02
【问题描述】:

为了在 ssl 中完成 Websockets 的握手,必须以阻塞模式读取套接字。使用流套接字,使用fwrite()fgets() 从php 后端与(javascript)客户端进行通信。在阻塞模式下,fgets() 会等到下一行进来,然后抢一行。建立套接字连接后,客户端会向 PHP 发送一些标头,以便完成握手。问题是,我想不出一种方法来找到标题末尾的位置,因为顺序取决于所使用的浏览器。

我将这项工作用于 chrome(因为 sec-websocket-extensions 行是发送的最后一个标头)

stream_set_blocking($lsSocketNew, true);
$lcHeader = "";
while($lcLine = fgets($lsSocketNew)){
  $lcHeader .= $lcLine;
  if(strstr($lcLine, "Sec-WebSocket-Extensions")){
    break;
  }
}

但这在其他浏览器(如 firefox)中不起作用,此标头是第一个发送的标头。 :P

(我认为fread() 应该做我正在寻找的事情——在阻塞模式下,当它进入时它应该在套接字上获取“所有内容”......但是当我尝试使用 fread 时,它是返回一个空白字符串。:P stream_get_contents() 是一样的)

【问题讨论】:

    标签: php sockets websocket stream


    【解决方案1】:

    虽然我不能给你一个 PHP 建议,但你可能需要考虑以下几点:

    我。你在寻找什么样的“一切”? TCP 中没有消息边界,因此“流中的所有内容”等同于“随机排序的数据量”。不幸的是,您不会神奇地读取所有 HTTP 标头并停在那里。

    II. 鉴于第一点,您必须找到将 HTTP 标头与 HTTP 正文分开的东西。这实际上相当简单,因为标题以blank line 结尾。因此,只需读取数据,直到收到CRLF CRLF*。在 PHP 中,您很可能会将 CRLF 视为 \n,尽管这可能取决于操作系统。

    III.如果你正在实现 websockets,使用fgets 是有问题的,因为协议的其余部分(在 HTTP 握手之后)是二进制的。您可能想要使用专用的 PHP 套接字模块和 socket_recv 而不是 fread。我不能说这两个函数有什么不同,但socket_* 函数只是 BSD 套接字的包装,它以多种语言实现。由于它们大多与语言无关,因此您可以在 Internet 上找到更多支持和教程。


    * 根据 HTTP 标准:

    CR = <US-ASCII CR, carriage return (13)>
    LF = <US-ASCII LF, linefeed (10)>
    

    【讨论】:

    • 像您在 (II) 中所说的那样寻找空行正是我想要的。我明白你在 (III) 中所说的,但 socket_recv() 仅适用于不是流套接字的套接字。流套接字有一个名为 stream_get_content() 的函数,但据我所知,这不支持阻塞,这是完成 ssl 握手所必需的。我尝试了各种方法,使用fgets() 是一种有效的方法。
    猜你喜欢
    • 2012-02-15
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 2013-10-15
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多