【发布时间】:2011-08-17 07:01:19
【问题描述】:
我正在尝试编写 Websockets 客户端和服务器。最初连接是 HTTP,Websockets 握手使用 HTTP 标头来指示连接需要升级到新协议。
我想从 SocketChannel 读取 HTTP 标头集,如果指示升级,则切换到不同的库来处理 Websocket,并从那时起以完全不同的方式处理 SocketChannel 流,作为一组帧而不是用 \r\n 分隔的行。
我知道我可以将任意数量的字节读入 ByteBuffer,但 Websockets 帧可能已随握手一起发送,我不想在这些代码段之间传递半消耗的缓冲区。我想要的是只从套接字读取直到并包括序列“\r\n\r\n”的数据。除了我想留在 SocketChannel 对象输入流中的任何数据。
推荐的方法是什么?从 SocketChannel 获取输入流并将其包装在缓冲阅读器中?这会与 NIO 正确交互,尤其是非阻塞使用吗?一旦检测到空行,我是否可以从输入流中删除缓冲读取器,并且在将通道传递给 Websockets 代码时仍然有所有可用的帧数据?
或者也许我需要逐字节读取(或者如果某些目标“\r\n\r\n”字符出现在块的末尾,则为 4 字节块和较小的缓冲区)并建立我的这样的标题字符串。
或者,如果缓冲区是直接分配的,那么操作标记、限制和位置的某种组合可能会允许输入流取回之前读取到 ByteBuffer 中的数据。
任何建议将不胜感激。
【问题讨论】:
-
你为什么不想传递一个半消耗缓冲区?您必须能够处理无法一次接收所有数据的情况,这会有什么不同?
-
一个 SocketChannel 没有输入流。它有一个接收缓冲区,这是你的意思吗?
-
Peter Lawley:我不想传递一个半消耗的缓冲区,因为它增加了握手代码和 websocket 帧代码之间的耦合。它们都必须使用 SocketChannel,因此无论如何都必须通过。如果我可以避免在它们之间传递另一个对象(更不用说缓冲区的状态,比如是否需要翻转),我认为这样会更干净。
-
EJP:我相信您可以通过调用 .socket().getInputStream() 从 SocketChannel 获取输入流。这就是我的意思。
-
但是您必须先将通道置于阻塞模式,然后在此之前从选择器中注销它,因此在单独的线程中读取,然后撤消所有这些......您也可以不完全使用 NIO。
标签: java nio readline websocket bytebuffer