php的原生websocket_PHP原生Socket.io实现TIM即时通讯的坑

本文介绍了PHP原生实现WebSocket即时通讯时遇到的问题及解决方案,包括使用`while(true)`+`sleep(1)`实现长连接,解包与打包代码示例,以及如何处理WebSocket心跳重连以应对超时关闭的情况。
摘要由CSDN通过智能技术生成

PHP原生Socket.io实现TIM即时通讯的坑

6cd5e4fd49658da7be73f2e8e3760c00.png

2年前

阅读 6473

评论 0

喜欢 0

## 1、长连接

原生PHP-Socket.io的长连接主要是使用`while(true)`+`服务器端堵塞`的方式实现的,这种长连接实现方式及其耗费性能,所以折中选择了一个优化的方案,鉴于博客没多少流量,我们在`whlie(true)`中使用了`sleep(1)`的方法,让循环1秒执行一次,这样降低了长连接的执行效率,释放了一部分内存,不过`WebSocket`会出现偶尔丢包的概率。

## 2、server服务端解包与打包代码

```php

/**

* 解码客户端发送过来的信息

* @param binary $buffer 客户端传来的信息

* @return String $decoded 解码后的字符串

*/

private function decodeMsg($buffer) {

$len = $masks = $data = $decoded = null;

$len = ord($buffer[1]) & 127;

if ($len === 126) {

$masks = substr($buffer, 4, 4);

$data = substr($buffer, 8);

} else if ($len === 127) {

$masks = substr($buffer, 10, 4);

$data = substr($buffer, 14);

} else {

$masks = substr($buffer, 2, 4);

$data = substr($buffer, 6);

}

$len = strlen($data);

for ($index = 0; $index < $len; $index++) {

$decoded .= $data[$index] ^ $masks[$index % 4];

}

return $decoded;

}

/**

* 发送到客户端前进行编码

* @param string $msg 发送到客户端的内容

*/

private function encodeMsg($msg) {

$len = strlen($msg);

if ($len <= 125) {

return "\x81" . chr($len) . $msg;

} else if ($len <= 65535) {

return "\x81" . chr(126) .pack("n", $len). $msg;

} else {

return "\x81" . chr(127) .pack("xxxxN", $len). $msg;

}

}

```

## 3、WebSocket心跳重连

WebSocket的API有个特点,是它有个超时机制,好像是1分钟内无任何数据传输操作,就主动发送关闭请求,这时候我们就需要自己用代码实现一个心跳操作,检测连接是否已经关闭,关闭的话则重新打开。

```javascript

var lockReconnect = false;//避免重复连接

var wsUrl = '你的server地址';

var ws;

var tt;

createWebSocket();

// ①开启WebSocket

function createWebSocket() {

try {

ws = new WebSocket(wsUrl);

init();

} catch(e) {

reconnect(wsUrl);

}

}

// ②初始化WebSocket,并设置心跳检测

function init() {

// 接收Socket断开时的消息通知

ws.onclose = function(){

console.log("断开socket连接了。。。试图重新连接。。。。");

reconnect(wsUrl);

};

// 接收Socket连接失败时的异常通知

ws.onerror = function(e){

console.log("ERROR:" + e.data);

reconnect(wsUrl);

};

// 连接成功

ws.onopen = function () {

console.log("握手成功,打开socket连接了。。。");

//心跳检测重置

heartCheck.start();

};

var message = '';

var flag = true;

// 接收服务端广播的消息通知

ws.onmessage = function(e){

heartCheck.start();

if (e.data == '123456789') { return false;}

message += e.data;

try {

obj = JSON.parse(e.data);

} catch(error_1) {

try {

obj = JSON.parse(message);

flag = true;

} catch (error_2) {

flag = false;

}

}

if (flag !== false) {

console.log(message);

message = '';

}

};

}

// ③ 掉线重连

function reconnect(url) {

if(lockReconnect) {

return;

};

lockReconnect = true;

//没连接上会一直重连,设置延迟避免请求过多

tt && clearTimeout(tt);

tt = setTimeout(function () {

createWebSocket(url);

lockReconnect = false;

}, 4000);

}

// ④心跳检测

var heartCheck = {

timeout: 3000,

timeoutObj: null,

serverTimeoutObj: null,

start: function(){

var self = this;

this.timeoutObj && clearTimeout(this.timeoutObj);

this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);

this.timeoutObj = setTimeout(function(){

//这里发送一个心跳,后端收到后,返回一个心跳消息,

//onmessage拿到返回的心跳就说明连接正常

ws.send("123456789");

//self.serverTimeoutObj = setTimeout(function() {

//ws.close();

// createWebSocket();

//}, self.timeout);

}, this.timeout)

}

}

```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值