Swoole从入门到入土(16)——WebSocket服务器[事件]
WIKI:
问:websocket协议虽然和http协议不同,但是兼容于http协议,如何判断客户端连接使用的是http协议?
答:通过使用 $server->connection_info($fd) 获取连接信息,返回的数组中有一项为 websocket_status,根据此状态可以判断是否为 WebSocket 客户端。
---------- 正文的分割线 -------------
Swoole\WebSocket\Server继承自Swoole\Http\Server,所以websocket server支持http server和tcp server的所有事件。另外,新增加了以下3个事件:
· onMessage (必选)
· onOpen 和 onHandShake (可选)
事件详解
onHandShake:WebSocket 建立连接后进行握手。WebSocket 服务器会自动进行 handshake 握手的过程,如果用户希望自己进行握手处理,可以设置 onHandShake 事件回调函数。
onHandShake(Swoole\Http\Request $request, Swoole\Http\Response $response);
· onHandShake 事件回调是可选的,需要自行处理 handshake 的时候,再设置这个回调函数。如果您不需要 “自定义” 握手过程,那么不要设置该回调,用 Swoole 默认的握手即可。
· 设置 onHandShake 回调函数后不会再触发 onOpen 事件,需要应用代码自行处理
· onHandShake 中必须调用 response->status() 设置状态码为 101 并调用 response->end() 响应,否则会握手失败.
· 内置的握手协议为 Sec-WebSocket-Version: 13,低版本浏览器需要自行实现握手
· 可以使用 server->defer 调用 onOpen 逻辑
示例:
$server->on('handshake', function (\Swoole\Http\Request $request, \Swoole\Http\Response $response) {
// print_r( $request->header );
// if (如果不满足我某些自定义的需求条件,那么返回end输出,返回false,握手失败) {
// $response->end();
// return false;
// }
// websocket握手连接算法验证
$secWebSocketKey = $request->header['sec-websocket-key'];
$patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#';
if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey))) {
$response->end();
return false;
}
echo $request->header['sec-websocket-key'];
$key = base64_encode(
sha1(
$request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
true
)
);
$headers = [
'Upgrade' => 'websocket',
'Connection' => 'Upgrade',
'Sec-WebSocket-Accept' => $key,
'Sec-WebSocket-Version' => '13',
];
// WebSocket connection to 'ws://127.0.0.1:9502/'
// failed: Error during WebSocket handshake:
// Response must not include 'Sec-WebSocket-Protocol' header if not present in request: websocket
if (isset($request->header['sec-websocket-protocol'])) {
$headers['Sec-WebSocket-Protocol'] = $request->header['sec-websocket-protocol'];
}
foreach ($headers as $key => $val) {
$response->header($key, $val);
}
$response->status(101);
$response->end();
});
onOpen:当 WebSocket 客户端与服务器建立连接并完成握手后会回调此函数。
onOpen(Swoole\WebSocket\Server $server, Swoole\Http\Request $request);
· $request 是一个 HTTP 请求对象,包含了客户端发来的握手请求信息
· onOpen 事件函数中可以调用 push 向客户端发送数据或者调用 close 关闭连接
· onOpen 事件回调是可选的
onMessage:当服务器收到来自客户端的数据帧时会回调此函数。
onMessage(Swoole\WebSocket\Server $server, Swoole\WebSocket\Frame $frame)
· $frame 是 Swoole\WebSocket\Frame 对象,包含了客户端发来的数据帧信息
· onMessage 回调必须被设置,未设置服务器将无法启动
· 客户端发送的 ping 帧不会触发 onMessage,底层会自动回复 pong 包,也可设置 open_websocket_ping_frame 参数手动处理
关于Swoole\WebSocket\Frame $frame

· $frame->data 如果是文本类型,编码格式必然是 UTF-8,这是 WebSocket 协议规定的

示例:
面向过程写法:
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
echo "server: handshake success with fd{$request->fd}\n";
});
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "this is server");
});
$server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
});
$server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
global $server;//调用外部的server
// $server->connections 遍历所有websocket连接用户的fd,给所有用户推送
foreach ($server->connections as $fd) {
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
if ($server->isEstablished($fd)) {
$server->push($fd, $request->get['message']);
}
}
});
$server->start();
面向对象写法:
class WebSocketTest
{
public $server; public function __construct()
{
$this->server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$this->server->on('open', function (Swoole\WebSocket\Server $server, $request) {
echo "server: handshake success with fd{$request->fd}\n";
});
$this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "this is server");
});
$this->server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
});
$this->server->on('request', function ($request, $response) {
// 接收http请求从get获取message参数的值,给用户推送
// $this->server->connections 遍历所有websocket连接用户的fd,给所有用户推送
foreach ($this->server->connections as $fd) {
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
if ($this->server->isEstablished($fd)) {
$this->server->push($fd, $request->get['message']);
}
}
});
$this->server->start();
}
} new WebSocketTest();
--------------------------- 我是可爱的分割线 ----------------------------
最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。
Swoole从入门到入土(16)——WebSocket服务器[事件]的更多相关文章
- Swoole学习(五)Swoole之简单WebSocket服务器的创建
环境:Centos6.4,PHP环境:PHP7 服务端代码 <?php //创建websocket服务器 $host = '0.0.0.0'; $port = ; $ws = new swool ...
- swoole创建websocket服务器
目录 1 安装准备 1.1 安装swoole前必须保证系统已经安装了下列软件 1.2 下载并解压 1.3 编译安装成功后,修改php.ini 2 构建Swoole基本实例 2.1 tcp服务器实例 2 ...
- 04.swoole学习笔记--webSocket服务器
<?php //创建webSocket服务器 $serv=); //获取请求 //on //open 建立连接 $serv:服务器 $request:客户端信息 $serv->on('op ...
- 实现一个websocket服务器-理论篇
本文是Writing WebSocket servers的中文文档,翻译自MDNWriting WebSocket servers.篇幅略长,个人能力有限难免有所错误,抛砖引玉共同进步. websoc ...
- 如何实现websocket服务器-理论篇
WebSocket 服务器简单来说就是一个遵循特殊协议监听服务器任意端口的tcp应用.搭建一个定制服务器的任务通常会让让人们感到害怕.然而基于实现一个简单的Websocket服务器没有那么麻烦. 一个 ...
- node实现一个WEBSOCKET服务器
早点时候翻译了篇实现一个websocket服务器-理论篇,简单介绍了下理论基础,本来打算放在一起,但是感觉太长了大家可能都看不下去.不过发现如果拆开的话,还是不可避免的要提及理论部分.用到的地方就简要 ...
- Erlang cowboy websocket 服务器
Erlang cowboy websocket 服务器 原文见于: http://marcelog.github.io/articles/erlang_websocket_server_cowboy_ ...
- 如何用Baas快速在腾讯云上开发小程序-系列1:搭建API & WEB WebSocket 服务器
版权声明:本文由贺嘉 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/221059001487422606 来源:腾云阁 h ...
- 用C语言实现websocket服务器
Websocket Echo Server Demo 背景 嵌入式设备的应用开发大都依靠C语言来完成,我去研究如何用c语言实现websocket服务器也是为了在嵌入式设备中实现一个ip camera的 ...
- netty系列之:使用netty搭建websocket服务器
目录 简介 netty中的websocket websocket的版本 FrameDecoder和FrameEncoder WebSocketServerHandshaker WebSocketFra ...
随机推荐
- [IDEA] - tomcat VM配置
-Dfile.encoding=UTF-8
- [转帖]L4LB for Kubernetes: Theory and Practice with Cilium+BGP+ECMP
http://arthurchiao.art/blog/k8s-l4lb/ Published at 2020-04-10 | Last Update 2020-08-22 1. Problem De ...
- [转帖]TLS 加速技术:Intel QuickAssist Technology(QAT)解决方案
https://zhuanlan.zhihu.com/p/631184323 3 人赞同了该文章 作者:vivo 互联网服务器团队- Ye Feng 本文介绍了 Intel QAT 技术方案,通过 ...
- [转帖]配置cri-docker使kubernetes1.24以docker作为运行时
从kubernetes 1.24开始,dockershim已经从kubelet中移除,但因为历史问题docker却不支持kubernetes主推的CRI(容器运行时接口)标准,所以docker不能再作 ...
- [转帖]create table INITRANS参数分析
https://www.modb.pro/db/44701 1. 内容介绍 Oracle数据库create table时使用INITRANS参数设置数据块ITL事务槽的数量,确保该数据块上 并发事务数 ...
- [转帖]等待事件 enq:TX - row lock contention分析与解决
6月30日,数据库发生了大量锁表.大概持续1小时,并且越锁越多.后来通过业务人员停掉程序,并kill掉会话后解决. 几天后再EM上查看CPU占用: CPU发生了明显等待. 主要是由于enq:TX - ...
- [转帖]ls 只显示目录
https://www.cnblogs.com/lavin/p/5912369.html 只显示目录: ls -d */ 在实际应用中,我们有时需要仅列出目录,下面是 4 种不同的方法. 1. 利用 ...
- [转帖]15.1. 插件dblink简介
https://help.kingbase.com.cn/v8.6.7.12/development/sql-plsql/ref-extended-plug-in/dblink.html dblink ...
- [转帖]基本系统调用性能lmbench测试方法和下载
简介 Lmbench是一套简易,可移植的,符合ANSI/C标准为UNIX/POSIX而制定的微型测评工具.一般来说,它衡量两个关键特征:反应时间和带宽. Lmbench旨在使系统开发者深入了解关键操作 ...
- forEach在项目中的使用
forEach 会改变原始数组 被forEach循环的数组不能够为空 forEach会改变原始数组 value是内容 index是索引 array是你写的数组. foeEach内部是异步的哈 功能描述 ...