本篇让我们先用一段示例代码开路:

<?php
Co\run(function () {
$server = new Co\Http\Server('0.0.0.0', 9501, false);
$server->handle('/', function ($request, $ws) {
$ws->upgrade();
while (true) {
$frame = $ws->recv();
if ($frame === '') {
$ws->push("bye bye");
$ws->close();
break;
} else if ($frame === false) {
echo "error : " . swoole_last_error() . "\n";
break;
} else {
if ($frame->data == 'close' || get_class($frame) === Swoole\WebSocket\CloseFrame::class) {
$ws->push("bye bye");
$ws->close();
return;
}
$ws->push("Hello {$frame->data}!");
$ws->push("How are you, {$frame->data}?");
}
}
}); $server->start();
});

这一段代码中,我们以协程的形式实例化了协程版本的http服务器。什么?你忘了什么是协程?那请先看这里==》传送门(Swoole从入门到入土(8)——协程初探)

每当有个新的客户端使用websocket向服务端发起连接请求时,服务端都会调用handle中使用的回调函数(即,有几个客户端连接,就有几次回调函数的调用),这些函数共同运行在一个协程容器内部。在回调函数内部,基本的处理流程如下:

· $ws->upgrade():向客户端发送 WebSocket 握手消息

· while(true) 循环处理消息的接收和发送

· $ws->recv() 接收 WebSocket 消息帧

· $ws->push() 向对端发送数据帧

· $ws->close() 关闭连接

其中:$ws 是一个 Swoole\Http\Response 对象。

接下来,让我们一起看一下$ws中每个成员函数的使用方法。

1) 函数upgrade():发送 WebSocket 握手成功信息。此方法不要用于异步风格的服务器中。

Swoole\Http\Response->upgrade(): bool

2) 函数recv():接收 WebSocket 消息。此方法不要用于异步风格的服务器中,调用 recv 方法时会挂起当前协程,等待数据到来时再恢复协程的执行。

Swoole\Http\Response->recv(double timeout = -1): Swoole\WebSocket\Frame | false | string

返回值:

成功收到消息,返回 Swoole\WebSocket\Frame 对象

object(Swoole\WebSocket\Frame)#1 (4) {
["fd"] => int(0)
["data"] => NULL
["opcode"] => int(1)
["finish"] => bool(true)
}

失败返回 false,请使用 swoole_last_error() 获取错误码
连接关闭返回空字符串

3) 函数push():发送 WebSocket 数据帧。此方法不要用于异步风格的服务器中,发送大数据包时,需要监听可写,因此会引起多次协程切换。

Swoole\Http\Response->push(string|object $data, int $opcode = 1, bool $finish = true): bool

· string|object $data:要发送的内容。若传入的 $data 是 Swoole\WebSocket\Frame 对象则其后续参数会被忽略,支持发送各种帧类型

· int $opcode:指定发送数据内容的格式 【默认为文本。发送二进制内容 $opcode 参数需要设置为 WEBSOCKET_OPCODE_BINARY】

· bool $finish:是否发送完成

4) 函数close():关闭 WebSocket 连接。此方法不要用于异步风格的服务器中,在 v4.4.15 以前版本会误报 Warning 忽略即可。

Swoole\Http\Response->close(): bool

最后,我们用群发的代码,来结束本篇内容。

看下面这一段代码时,我们要注意,因为所有的回调函数是运行在同一个协程容器内部,即存在同一个进程中(甚至是同一个线程中),所以全局变量在这里是可以安心使用的

function getObjectId(\Swoole\Http\Response $response) {
if (PHP_VERSION_ID < 70200) {
$id = spl_object_hash($response);
} else {
$id = spl_object_id($response);
}
return $id;
} Co\run(function () {
$server = new Co\Http\Server('127.0.0.1', 9502, false);
$server->handle('/websocket', function ($request, $ws) {
$ws->upgrade();
global $wsObjects;
$objectId = getObjectId($ws);
$wsObjects[$objectId] = $ws;
while (true) {
$frame = $ws->recv();
if ($frame === '') {
unset($wsObjects[$objectId]);
$ws->close();
break;
} else if ($frame === false) {
echo 'error : ' . swoole_last_error() . "\n";
break;
} else {
if ($frame->data == 'close' || get_class($frame) === Swoole\WebSocket\CloseFrame::class) {
unset($wsObjects[$objectId]);
$ws->close();
return;
}
foreach ($wsObjects as $obj) {
$obj->push("Server:{$frame->data}");
}
}
}
});
$server->start();
});

本篇内容到此结束,下一篇我们将一起了解swoole的毫秒定时器。

---------------------------  我是可爱的分割线  ----------------------------

最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。

Swoole从入门到入土(20)——WebSocket服务器[协程版本]的更多相关文章

  1. Swoole 中使用通道(Channel)实现协程间通讯(消息队列)

    通道 Coroutine\Channel 使用本地内存,不同的进程之间内存是隔离的. 只能在同一进程的不同协程内进行 push 和 pop 操作. Co::set(['hook_flags'=> ...

  2. flask服务器 + 协程 + 爬虫 + ui自动化

    公司有个爬取的需求,要求持续性爬取,需要永久性地挂载到目标网站上,每天爬一次里面的数据.数据有下载表格的,我通过ui自动化点击拿到数据:还有一部分数据是几乎所有的图片信息,信息量近百万,这部分用scr ...

  3. Web服务器-并发服务器-协程 (3.4.2)

    @ 目录 1.分析 2.代码 关于作者 1.分析 随着网站的用户量越来愈多,通过多进程多线程的会力不从心 使用协程可以缓解这一问题 只要使用gevent实现 2.代码 from socket impo ...

  4. Swoole 中使用 TCP 异步服务器、TCP 协程服务器、TCP 同步客户端、TCP 协程客户端

    TCP 异步风格服务器 异步风格服务器通过监听事件的方式来编写程序.当对应的事件发生时底层会主动回调指定的函数. 由于默认开启协程化,在回调函数内部会自动创建协程,遇到 IO 会产生协程调度,异步风格 ...

  5. swoole深入学习 8. 协程 转

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/yangyi2083334/article/ ...

  6. swoole 协程介绍

    协程的执行顺序: 1 2 3 4 5 6 7 8 9 go(function () {     echo "hello go1 \n"; });   echo "hell ...

  7. 用python实现自己的http服务器——多进程、多线程、协程、单进程非堵塞版、epoll版

    了解http协议 http请求头 GET / HTTP/1.1 Host: www.baidu.com Connection: keep-alive Pragma: no-cache Cache-Co ...

  8. 比物理线程都好用的C++20的协程,你会用吗?

    摘要:事件驱动(event driven)是一种常见的代码模型,其通常会有一个主循环(mainloop)不断的从队列中接收事件,然后分发给相应的函数/模块处理.常见使用事件驱动模型的软件包括图形用户界 ...

  9. vs2019 16.8更新之后的 C++20 协程co_yield用法

    由于搜索出来的帖子,都是老版本的实验协程,很多老的代码已经失去参考性,并且很复杂,所以就自己研究了一下. 1 #include <iostream> 2 #include <coro ...

  10. swoole创建websocket服务器

    目录 1 安装准备 1.1 安装swoole前必须保证系统已经安装了下列软件 1.2 下载并解压 1.3 编译安装成功后,修改php.ini 2 构建Swoole基本实例 2.1 tcp服务器实例 2 ...

随机推荐

  1. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2024.01.13)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  2. [转帖]自动清理_详解centos7和centos6系统的/tmp目录自动清理规则及区别

    概述 分享最近应用碰到的一个奇怪bug,一开始以为是代码上的问题,找了一段时间发现居然是因为系统的一个自动清理规则导致,下面一起来看看吧~ 一.应用报错: logwire.core.exception ...

  3. [转帖]Nginx优化与防盗链

    目录 一.配置Nginx隐藏版本号 1.第一种方法修改配置文件 2.第二种方法修改源码文件,重新编译安装 二.修改Nginx用户与组 三.配置Nginx网页缓存时间 四.实现Nginx的日志分割 五. ...

  4. [转帖]jmeter之使用csv文件传递参数-05篇

    csv文件格式,第一列为手机号,第二列为密码 1.右键添加一个配置元件---csv数据文件设置 2.设置csv数据提取路径 3.引用数据 4.设置线程循环运行两次,然后发送请求 看到结果就执行了两次, ...

  5. [转帖]iometer - 性能压力测试工具

    <存储工具系列文章>主要介绍存储相关的测试和调试工具,包括不限于dd.fio.vdbench.iozone.iometer.cosbench等性能负载工具,及strace等调试工具. 1 ...

  6. Python学习之三: 编译二进制

    Python学习之三: 编译二进制 摘要 每次使用python 执行py文件其实是比较麻烦的 主要是还得安装python的虚拟机,以及安装对应的pip包. 感觉比较繁杂 理论上最快捷的方式是编译成 二 ...

  7. 【转帖】Linux创建软连接出现的错误及解决方法

    问题: 创建软连接以后,使用cd 软连接路径显示没有那个文件或目录. 创建过程及切换结果,如图: 原因: 路径一定要写成绝对路径!!! 解决办法: 了解创建软连接的命令: ln -s 源文件 目标文件 ...

  8. [转帖]从CPU指令集自主到信息技术产业自主

    https://zhuanlan.zhihu.com/p/365210753 现代信息技术的应用都是以计算机为基础,CPU是计算机中的信息处理中枢.CPU指令集是CPU逻辑电路与操作系统和应用程序交流 ...

  9. [转帖]在龙芯3A5000上测试SPEC CPU 2006

    https://baijiahao.baidu.com/s?id=1707601012673143593&wfr=spider&for=pc 注:百家号中,一些文本.代码等的排版格式无 ...

  10. [转帖]tubostat

    TURBOSTAT(8) System Manager's Manual TURBOSTAT(8) NAME turbostat - Report processor frequency and id ...