【发布时间】:2018-03-25 00:08:40
【问题描述】:
我正在用 PHP 编写一个 websocket 服务器(使用 sockets 扩展名),我需要一些帮助来了解我需要在多大程度上处理碎片消息。
我对websocket信息如何传递的理解如下:
- 客户端应用程序将
MESSAGE(任意长度)发送到客户端 API。 - 客户端 API 将
MESSAGE拆分为一个或多个FRAMES(也是任意长度)并将它们发送到网络层。 - 网络层将数据拆分成多个
PACKETS,通过TCP通过网络发送。 - 服务器接收 TCP
PACKETS(可能是乱序的,但如有必要,它会重新排序)并将它们传递给正在侦听相关端口的应用程序。 - 应用调用
socket_recv()从socket读取接收到的数据。
我想了解的是我的应用程序在使用socket_recv() 读取 websocket 数据流时会看到什么数据?
具体来说,我需要在多大程度上担心碎片化?
为了帮助解释我的问题,以下是上述过程的图表形式:
1. Web app (messages): [Message_1][Message_2]
2. Browser (frames) : [Messag][e_1][Messag][e_2]
3. TCP send (packets) : [Mess][ag][e_1][Mess][ag][e_2]
4. TCP recv (packets) : [ag][Mess][e_2][ag][Mess][e-1]
5. socket_recv : ???
如果我在循环中调用socket_recv(),直到它返回长度为零(每次都添加到我的内部缓冲区),我能保证得到一个完整的MESSAGE吗?
socketrecv: [Message_1]
socketrecv: [Message_2]
还是一个完整的FRAME?
socketrecv: [Messag]
socketrecv: [e_1]
socketrecv: [Messag]
socketrecv: [e_2]
或者,它实际上会是一个任意系列的PACKETS,代表迄今为止收到的任何数据(因此可能是部分FRAME,甚至是多个FRAMES)?
socketrecv: [Messag
socketrecv: e_1][Mess
socketrecv:
socketrecv: ag
socketrecv: e_2]
还是别的什么?
我很高兴将各种FRAMES 数据拼接在一起,但如果我可以假设每次轮询中接收到的数据的第一个字节(使用socket_select() 发起)总是@ 987654341@ 标头,而不必将其作为原始字节流处理,在开始之前需要将其缝合回FRAMES。
【问题讨论】:
-
您的问题得到答复了吗?我对这样的解释很感兴趣,但找不到任何相关信息:/
-
不——还没有。我的实现假设帧按发送顺序出现,但是从套接字读取的任何内容都可能包含此数据的任意片段。因此,我有两个缓冲区:流缓冲区,包含从套接字读取的原始字节,以及帧缓冲区,它包含完整的帧,一旦它们被完全接收。不知道这是必需的还是只是大刀阔斧,但在没有答案的情况下,这是最安全的方法,而且似乎效果很好。
-
感谢您的回复,我会尝试类似的东西