PHP Websocket接收不完整的数据 [英] PHP Websocket receiving incomplete data

查看:85
本文介绍了PHP Websocket接收不完整的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码可以使用 websocket 接收数据.

I have the following code to receive data with a websocket.

$bytes=socket_recv($socket,$buffer2,1024,0);
$datarec=unmask($buffer2);
//process further

这有效,但很多时候我收到不完整的消息并且我无法进一步处理数据.

This works but many time I get incomplete messages and I am unable to process the data further.

我想出了以下解决方案.

I have come up with following solution.

基本上我保留了数据长度的前 10 位数字,在使用 socket.send 从 javascript 发送之前,我在消息的开头添加了数据的长度.因此,如果我的消息是你好,这是一条消息",它会变成30:sizehello 这是一条消息",我会补偿添加的30:size".

Basically I reserve the first 10 digits for length of the data and before sending it using socket.send from javascript I add the length of the data at start of message. So if my message is "hello this is a message" it becomes "30:sizehello this is a message" I compensate for the added "30:size".

在php方面我希望这样做

On the php side I hope to do this

首先读取 10 位数字.

First read the 10 digits.

$length=socket_recv($socket,$buffer2,1024,MSG_WAITALL);

然后使用类似

$datarec=aocket_recv($socket,$buffer2,$length,MSG_WAITALL);

遗憾的是,这不起作用,因为我无法读取和取消屏蔽第二次使用 socket_recv 接收的数据.

Sadly, this does not work as I am unable to read and unmask the data received with socket_recv 2nd time.

关于如何确保在不知道数据长度的情况下从 websocket 获取完整数据的任何建议.谢谢你的帮助.

Any suggestions on how to make sure you get complete data from websocket without knowing the data length before hand. Thanks for your help.

推荐答案

此问题的解决方法如下

问题:当使用 websocket 和类似 socket_recv($socket,$buffer,5000,0); 之类的东西接收长字节数据时,您可能无法获得完整的数据在一次调用中,您需要再次调用 socket_recv($socket,$buffer,5000,0);.

Issue: When receiving long bytes of data using websocket with something like socket_recv($socket,$buffer,5000,0); you may not get the complete data in single call and you need to call socket_recv($socket,$buffer,5000,0); again.

例如,假设我们使用 JS (socket.send) 从浏览器向 websocket 发送了 8000 字节的数据.在服务器端,我们将使用 socket_recv 来获取消息.但是我们可能只先接收到大约 4000 字节的数据,可能需要再次调用 socket_recv 来获取剩余的 4000 字节.

For example, lets suppose we sent 8000 bytes of data from browser to websocket with JS (socket.send). On server side we will use socket_recv to get the message. But we may only receive about 4000 bytes of data first and may need to call socket_recv again to get the remaining 4000 bytes.

现在在我的原始代码中,我曾经在调用 socket_recv 以取消屏蔽数据后立即调用函数unmask".这适用于收到的第一组消息.但是对于下一组消息,unmask"函数将尝试提取新的 Mask 并应用它.这是错误,因为该消息是上一条消息的延续,而 Mask 没有改变.解决方案是保留第一条消息的掩码并检查下一条消息是否继续.这可以通过检查消息的第一位来完成.

Now in my original code I used to call the function "unmask" right after calling socket_recv to unmask the data. This would work for the first set of message received. But for the next set of message the "unmask" function would try to extract new Mask and apply that. This was the error since the message is continuation of previous message and Mask does not change. The solution is to keep the mask from first message and check if next message is continuation or not. This can be done by checking first bit of message.

$fin=ord($payload[0]) & 0x77;

如果 $fin 为 1,则该消息是一条新消息,如果不是,则它是上一条消息的延续.在 ($fin!=1) 的情况下,您需要使用之前消息的掩码来取消对消息的掩码.不要忘记,由于您需要再次使用 mask 的值,因此您需要在函数外部定义它并使其成为全局变量.

if $fin is 1 the message is a new message if not it is continuation of previous message. In case of ($fin!=1) you need to use mask of your previous message to unmask the message. Don't forget, since you need to to use the value of mask again you need to define it outside the function and make it global.

我在下面提供了新旧代码供您参考.我希望这是正确的解决方案,但请随时添加任何内容或让我知道我是否在任何地方出错.

I have provided the old and new code below for your reference. I hope this is the right solution but please feel free to add anything or let me know if I went wrong anywhere.

My Original Unmask 功能:

function unmask($payload) {
    $length = ord($payload[1]) & 127;
    if($length == 126) {
        $masks = substr($payload, 4, 4);
        $data = substr($payload, 8);
        $firstcode=substr($payload, 1, 1);
    }


    elseif($length == 127) {
        $masks = substr($payload, 10, 4);
        $data = substr($payload, 14);
        $firstcode=substr($payload, 1, 1);

        }
    else {
        $masks = substr($payload, 2, 4);
        $data = substr($payload, 6);
        $firstcode=substr($payload, 1, 1);

    }
    $text = '';
for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }

    return $text;
}

更新功能:

function unmask($payload,$masks) {
global $masks;
$fin=ord($payload[0]) & 0x77;

if($fin!=1){    
    $data=substr($payload,0);
     $text='';
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }
    return $text;
}else{
    $length = ord($payload[1]) & 127;

    Echo "Mask functiion Payload Lenght".$length."\n";


    if($length == 126) {
        $masks = substr($payload, 4, 4);
        $data = substr($payload, 8);
    }


    elseif($length == 127) {
        $masks = substr($payload, 10, 4);
        $data = substr($payload, 14);

        }
    else {
        $masks = substr($payload, 2, 4);
        $data = substr($payload, 6);

    }
    $text = '';
for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }   
    return $text;
}

}

这篇关于PHP Websocket接收不完整的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆