本帖最后由 Akkariin 于 2018-12-7 08:55 编辑
# 什么是 WebSocket
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信 —— 允许服务器主动发送信息给客户端。
WebSocket 通信协议于 2011 年被 IETF 定为标准 RFC 6455,并被 RFC7936 所补充规范。
# 什么是 Swoole
Swoole 是一个 PHP 扩展,扩展不是为了提升网站的性能,是为了提升网站的开发效率。最少的性能损耗,换取最大的开发效率。利用 Swoole 扩展,开发一个复杂的 Web 功能,可以在很短的时间内完成了。
今天,我要给大家带来的就是 WebSocket 的基础应用教程。首先举个例子,传统我们想要保持网页上的内容实时刷新,有什么办法呢?那就是通过 AJAX 轮询,而这种方法,会发起大量短连接请求,这对于 PHP 来说,单用户没什么影响,但是如果遇到了多用户的情况,就很容易出现网站反应迟钝,或者打不开的情况。
不知道各位有没有遇到过网站服务器被 CC 攻击的情况,当有黑客向你的服务器发起大量连接,你的服务器就会因为承受不了高并发的请求量而崩溃。
而如果 AJAX 短连接数量过多,请求次数过于频繁的时候,效果就和 CC 攻击差不多了,让普通用户攻击你的网站,自 己 坑 自 己。
那么有什么办法在不发起短连接的情况下还能实时刷新网页内容呢?答案就是 WebSocket。
其实 AJAX 严格意义上都不能算是实时刷新,因为轮询请求是存在延迟的,我们先简单了解下 AJAX 和 WebSocket 的工作原理。
AJAX 工作原理
WebSocket 工作原理
从这个简单的例子可以看出,WebSocket 只需要客户端和服务器建立一条长连接,就可以实时推送消息了,而不需要客户端频繁向服务器发起请求。
第一节省了时间,因为每次发起新连接都需要时间。
第二降低了处理每个连接的开销,少量连接可能还感觉不出来,但是连接量大了差异就很明显了。
# 什么是 WebSocket
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信 —— 允许服务器主动发送信息给客户端。
WebSocket 通信协议于 2011 年被 IETF 定为标准 RFC 6455,并被 RFC7936 所补充规范。
# 什么是 Swoole
Swoole 是一个 PHP 扩展,扩展不是为了提升网站的性能,是为了提升网站的开发效率。最少的性能损耗,换取最大的开发效率。利用 Swoole 扩展,开发一个复杂的 Web 功能,可以在很短的时间内完成了。
今天,我要给大家带来的就是 WebSocket 的基础应用教程。首先举个例子,传统我们想要保持网页上的内容实时刷新,有什么办法呢?那就是通过 AJAX 轮询,而这种方法,会发起大量短连接请求,这对于 PHP 来说,单用户没什么影响,但是如果遇到了多用户的情况,就很容易出现网站反应迟钝,或者打不开的情况。
不知道各位有没有遇到过网站服务器被 CC 攻击的情况,当有黑客向你的服务器发起大量连接,你的服务器就会因为承受不了高并发的请求量而崩溃。
而如果 AJAX 短连接数量过多,请求次数过于频繁的时候,效果就和 CC 攻击差不多了,让普通用户攻击你的网站,自 己 坑 自 己。
那么有什么办法在不发起短连接的情况下还能实时刷新网页内容呢?答案就是 WebSocket。
其实 AJAX 严格意义上都不能算是实时刷新,因为轮询请求是存在延迟的,我们先简单了解下 AJAX 和 WebSocket 的工作原理。
AJAX 工作原理
WebSocket 工作原理
从这个简单的例子可以看出,WebSocket 只需要客户端和服务器建立一条长连接,就可以实时推送消息了,而不需要客户端频繁向服务器发起请求。
第一节省了时间,因为每次发起新连接都需要时间。
第二降低了处理每个连接的开销,少量连接可能还感觉不出来,但是连接量大了差异就很明显了。
# 环境依赖
建议使用 Ubuntu14、CentOS7 或更高版本的操作系统
# PHP版本依赖
不依赖 PHP 的 stream、sockets、pcntl、posix、sysvmsg 等扩展。PHP 只需安装最基本的扩展即可
# ARM平台(树莓派Raspberry PI)
# MIPS平台(OpenWrt路由器)
# CygWin环境支持(Windows系统)
swoole-1.7.7 增加了对 cygwin 环境的支持,在 Windows 环境下,可以直接使用 cygwin + php 来跑 swoole 程序。
cygwin 模式下需要对 PHP 进行简化,去掉不使用的扩展,避免进程占用内存过大,导致 Fork 操作失败
# BashOnWindows
Windows 10 系统增加了 Linux 子系统支持,BashOnWindows 环境下也可以使用 swoole。安装命令
# DockerOnWindows
在 Windows 下开发可以使用 Hyper-V+Docker 来方便的开发 Swoole 应用,安装好 Docker 后再 Settings 里的 Shared Droves 选项里共享代码所在磁盘。然后使用如下命令来快速启动 Docker 容器。
# 编译安装
Swoole 扩展是按照 PHP 标准扩展构建的。使用 phpize 来生成编译检测脚本,./configure 来做编译配置检测,make 进行编译,make install 进行安装。
# 安装准备
安装前必须保证系统已经安装了下列软件
# 下载地址
下载源代码包后,在终端进入源码目录,执行下面的命令进行编译和安装
# 新手编译示例
# 进阶完整编译示例
初次接触swoole的开发者请先尝试上方的简单编译,如果有进一步的需要,可以根据具体的需求和版本,调整以下示例的编译参数
编译参数参考
以下脚本会下载并编译master分支的源码, 需保证你已安装所有依赖, 否则会遇到各种依赖错误
# PECL
Swoole项目已收录到PHP官方扩展库,除了手工下载编译外,还可以通过PHP官方提供的pecl命令,一键下载安装
# 配置php.ini
编译安装成功后,修改php.ini加入
通过 php -m 或 phpinfo() 来查看是否成功加载了 swoole.so,如果没有可能是 php.ini 的路径不对,可以使用 php --ini 来定位到 php.ini 的绝对路径。
# WebSocket 服务端代码
编写一个简单的 WebSocket 服务器。
这就是一个简单的 ECHO 服务器,你发送什么它就会返回什么。
介绍
$server 是 WebSocket 服务器实例的变量,这个服务器运行在 9501 端口,允许任何 IP 连接(0.0.0.0)
介绍一下几个事件
$server->start() 是启动已创建的实例。
简单聊天室程序
下面我们来写一个简单的例子,一个网页在线聊天室。
介绍
foreach($server->connections as $key => $fd)
这段代码的作用呢,是遍历当前所有客户端连接,作用就是为了给每个客户端都发送一条消息(通过 push 方法)
客户端
我们简单写一个网页对接一下服务端。
效果如下

# 关于 SSL 问题
请注意,如果你的网站是 https 的,而 WebSocket 是普通的 ws 协议,那么会导致无法连接,这是浏览器的安全设定。因为 ws 协议是非加密的,你需要使用 wss 协议(即 WebSocket + SSL)。
以下是 Nginx 反向代理 WebSocket 增加 SSL 的相关配置。
# 相关 Demo
我自己写的论坛程序评论功能已经改成了实时刷新,同时增加了在线人数统计的功能,这一切都是 WebSocket 的功劳。
https://www.zerobbs.net/
感谢阅读,如果这篇文章对你有帮助,欢迎评分。
# 什么是 WebSocket
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信 —— 允许服务器主动发送信息给客户端。
WebSocket 通信协议于 2011 年被 IETF 定为标准 RFC 6455,并被 RFC7936 所补充规范。
# 什么是 Swoole
Swoole 是一个 PHP 扩展,扩展不是为了提升网站的性能,是为了提升网站的开发效率。最少的性能损耗,换取最大的开发效率。利用 Swoole 扩展,开发一个复杂的 Web 功能,可以在很短的时间内完成了。
今天,我要给大家带来的就是 WebSocket 的基础应用教程。首先举个例子,传统我们想要保持网页上的内容实时刷新,有什么办法呢?那就是通过 AJAX 轮询,而这种方法,会发起大量短连接请求,这对于 PHP 来说,单用户没什么影响,但是如果遇到了多用户的情况,就很容易出现网站反应迟钝,或者打不开的情况。
不知道各位有没有遇到过网站服务器被 CC 攻击的情况,当有黑客向你的服务器发起大量连接,你的服务器就会因为承受不了高并发的请求量而崩溃。
而如果 AJAX 短连接数量过多,请求次数过于频繁的时候,效果就和 CC 攻击差不多了,让普通用户攻击你的网站,自 己 坑 自 己。
那么有什么办法在不发起短连接的情况下还能实时刷新网页内容呢?答案就是 WebSocket。
其实 AJAX 严格意义上都不能算是实时刷新,因为轮询请求是存在延迟的,我们先简单了解下 AJAX 和 WebSocket 的工作原理。
AJAX 工作原理
客户端:Hi 服务器,有没有新内容可以更新?
服务器:没有,请稍等一会再来。
过了一会……
客户端:Hi 服务器,有没有新内容可以更新?
服务器:没有,请稍等一会再来。
又过了一会……
客户端:Hi 服务器,有没有新内容可以更新?
服务器:好的,这是新的内容,balabala...
WebSocket 工作原理
客户端:Hi 服务器,我是客户端 01,如果有新消息请告诉我。
服务器:好的,已经和你建立连接,稍后有新消息我会推送给你。
过了一会……
服务器:有新消息了,内容是 balabala...
客户端:已收到消息
从这个简单的例子可以看出,WebSocket 只需要客户端和服务器建立一条长连接,就可以实时推送消息了,而不需要客户端频繁向服务器发起请求。
第一节省了时间,因为每次发起新连接都需要时间。
第二降低了处理每个连接的开销,少量连接可能还感觉不出来,但是连接量大了差异就很明显了。
2021.12 数据,可能有更多内容
# 什么是 WebSocket
WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信 —— 允许服务器主动发送信息给客户端。
WebSocket 通信协议于 2011 年被 IETF 定为标准 RFC 6455,并被 RFC7936 所补充规范。
# 什么是 Swoole
Swoole 是一个 PHP 扩展,扩展不是为了提升网站的性能,是为了提升网站的开发效率。最少的性能损耗,换取最大的开发效率。利用 Swoole 扩展,开发一个复杂的 Web 功能,可以在很短的时间内完成了。
今天,我要给大家带来的就是 WebSocket 的基础应用教程。首先举个例子,传统我们想要保持网页上的内容实时刷新,有什么办法呢?那就是通过 AJAX 轮询,而这种方法,会发起大量短连接请求,这对于 PHP 来说,单用户没什么影响,但是如果遇到了多用户的情况,就很容易出现网站反应迟钝,或者打不开的情况。
不知道各位有没有遇到过网站服务器被 CC 攻击的情况,当有黑客向你的服务器发起大量连接,你的服务器就会因为承受不了高并发的请求量而崩溃。
而如果 AJAX 短连接数量过多,请求次数过于频繁的时候,效果就和 CC 攻击差不多了,让普通用户攻击你的网站,自 己 坑 自 己。
那么有什么办法在不发起短连接的情况下还能实时刷新网页内容呢?答案就是 WebSocket。
其实 AJAX 严格意义上都不能算是实时刷新,因为轮询请求是存在延迟的,我们先简单了解下 AJAX 和 WebSocket 的工作原理。
AJAX 工作原理
客户端:Hi 服务器,有没有新内容可以更新?
服务器:没有,请稍等一会再来。
过了一会……
客户端:Hi 服务器,有没有新内容可以更新?
服务器:没有,请稍等一会再来。
又过了一会……
客户端:Hi 服务器,有没有新内容可以更新?
服务器:好的,这是新的内容,balabala...
服务器:没有,请稍等一会再来。
过了一会……
客户端:Hi 服务器,有没有新内容可以更新?
服务器:没有,请稍等一会再来。
又过了一会……
客户端:Hi 服务器,有没有新内容可以更新?
服务器:好的,这是新的内容,balabala...
WebSocket 工作原理
客户端:Hi 服务器,我是客户端 01,如果有新消息请告诉我。
服务器:好的,已经和你建立连接,稍后有新消息我会推送给你。
过了一会……
服务器:有新消息了,内容是 balabala...
客户端:已收到消息
服务器:好的,已经和你建立连接,稍后有新消息我会推送给你。
过了一会……
服务器:有新消息了,内容是 balabala...
客户端:已收到消息
从这个简单的例子可以看出,WebSocket 只需要客户端和服务器建立一条长连接,就可以实时推送消息了,而不需要客户端频繁向服务器发起请求。
第一节省了时间,因为每次发起新连接都需要时间。
第二降低了处理每个连接的开销,少量连接可能还感觉不出来,但是连接量大了差异就很明显了。
# 环境依赖
- 仅支持 Linux、FreeBSD、MacOS 三种操作系统
- 在 Windows 平台,可使用 CygWin 或 WSL(Windows Subsystem for Linux)
- Linux 内核版本 2.3.32 以上
- gcc4.4 以上版本或者 clang
- 4.x 版本起需要 gcc-4.8 或更高版本, 编译失败请先尝试升级 gcc
- 编译为 libswoole.so 作为 C/C++ 库时需要使用 cmake-2.4 或更高版本
建议使用 Ubuntu14、CentOS7 或更高版本的操作系统
# PHP版本依赖
- Swoole-1.x 需要 PHP-5.3.10 或更高版本
- Swoole-2.x 需要 PHP-7.0.0 或更高版本
- Swoole-4.x 需要 PHP-7.1.0 或更高版本
不依赖 PHP 的 stream、sockets、pcntl、posix、sysvmsg 等扩展。PHP 只需安装最基本的扩展即可
# ARM平台(树莓派Raspberry PI)
- 请使用 1.7.10 或更高版本
- 使用 GCC 交叉编译
- 在编译 Swoole 时,需要手工修改 Makefile 去掉 -O2 编译参数
# MIPS平台(OpenWrt路由器)
- 请使用 swoole-1.7.21 或更高版本
- 使用 GCC 交叉编译
# CygWin环境支持(Windows系统)
swoole-1.7.7 增加了对 cygwin 环境的支持,在 Windows 环境下,可以直接使用 cygwin + php 来跑 swoole 程序。
- 安装 cygwin,并安装 gcc、make、autoconf、php 4个包
- 下载 swoole 源码,在 cygwin-shell 中进行 phpize/configure/make/make install
- 修改 php.ini,加入 swoole.so
cygwin 模式下需要对 PHP 进行简化,去掉不使用的扩展,避免进程占用内存过大,导致 Fork 操作失败
# BashOnWindows
Windows 10 系统增加了 Linux 子系统支持,BashOnWindows 环境下也可以使用 swoole。安装命令
代码:
- apt-get install php7.0 php7.0-curl php7.0-gd php7.0-gmp php7.0-json php7.0-mysql php7.0-opcache php7.0-readline php7.0-sqlite3 php7.0-tidy php7.0-xmlphp7.0-bcmath php7.0-bz2 php7.0-intl php7.0-mbstringphp7.0-mcrypt php7.0-soap php7.0-xslphp7.0-zip
- pecl install swoole
- echo 'extension=swoole.so' >> /etc/php/7.0/mods-available/swoole.ini
- cd /etc/php/7.0/cli/conf.d/ && ln -s ../../mods-available/swoole.ini 20-swoole.ini
- cd /etc/php/7.0/fpm/conf.d/ && ln -s ../../mods-available/swoole.ini 20-swoole.ini
- BashOnWindows 环境下必须关闭 daemonize 选项
- 需要修改 config.h 关闭 HAVE_SIGNALFD
# DockerOnWindows
在 Windows 下开发可以使用 Hyper-V+Docker 来方便的开发 Swoole 应用,安装好 Docker 后再 Settings 里的 Shared Droves 选项里共享代码所在磁盘。然后使用如下命令来快速启动 Docker 容器。
代码:
- docker run --rm -t -i --name myapp -p 9501:9501 -v e:/path/to:/app:rw xutongle/php:7.1-fpm /bin/bash
- e:/path/to 为源码所在路径
- /app 为容器内路径
- 在 bash 里执行 cd /app && php server.php
# 编译安装
Swoole 扩展是按照 PHP 标准扩展构建的。使用 phpize 来生成编译检测脚本,./configure 来做编译配置检测,make 进行编译,make install 进行安装。
- 请下载 releases 版本的 swoole,直接从 github 主干上拉取最新代码可能会编译不过
- 如无特殊需求, 请务必编译安装 swoole 的最新版本
- 如果当前用户不是 root,可能没有 PHP 安装目录的写权限,安装时需要 sudo 或者 su
- 如果是在 git 分支上直接 git pull 更新代码,重新编译前务必要执行 make clean
# 安装准备
安装前必须保证系统已经安装了下列软件
- php-7.0 或更高版本
- gcc-4.8 或更高版本
- make
- autoconf
- pcre (CentOS 系统可以执行命令:yum install pcre-devel)
# 下载地址
- https://github.com/swoole/swoole-src/releases
- http://pecl.php.net/package/swoole
- http://git.oschina.net/swoole/swoole
下载源代码包后,在终端进入源码目录,执行下面的命令进行编译和安装
# 新手编译示例
代码:
- cd swoole
- sudo phpize (ubuntu 没有安装phpize可执行命令:sudo apt-get install php-dev来安装phpize)
- sudo ./configure
- sudo make
- sudo make install
# 进阶完整编译示例
初次接触swoole的开发者请先尝试上方的简单编译,如果有进一步的需要,可以根据具体的需求和版本,调整以下示例的编译参数
编译参数参考
以下脚本会下载并编译master分支的源码, 需保证你已安装所有依赖, 否则会遇到各种依赖错误
代码:
- mkdir -p ~/build && \
- cd ~/build && \
- rm -rf ./swoole-src && \
- curl -o ./tmp/swoole.tar.gz https://github.com/swoole/swoole-src/archive/master.tar.gz -L && \
- tar zxvf ./tmp/swoole.tar.gz && \
- mv swoole-src* swoole-src && \
- cd swoole-src && \
- phpize && \
- ./configure \
- --enable-coroutine \
- --enable-openssl\
- --enable-http2\
- --enable-async-redis \
- --enable-sockets \
- --enable-mysqlnd && \
- make clean && make && sudo make install
# PECL
Swoole项目已收录到PHP官方扩展库,除了手工下载编译外,还可以通过PHP官方提供的pecl命令,一键下载安装
代码:
- pecl install swoole
# 配置php.ini
编译安装成功后,修改php.ini加入
代码:
- extension=swoole.so
# WebSocket 服务端代码
编写一个简单的 WebSocket 服务器。
代码:
- $server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
- $server->on('open', function (Swoole\WebSocket\Server $server, $request) {
- echo "有新的客户端连接,识别 ID 为:{$request->fd}\n";
- });
- $server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
- echo "客户端 {$frame->fd} 发送了:{$frame->data}\n";
- $server->push($frame->fd, "你发送了:{$frame->data}\n");
- });
- $server->on('close', function ($server, $fd) {
- echo "客户端 {$fd} 已离线\n";
- });
- $server->start();
介绍
$server 是 WebSocket 服务器实例的变量,这个服务器运行在 9501 端口,允许任何 IP 连接(0.0.0.0)
介绍一下几个事件
- open 是当有新连接的时候执行的事件
- message 是当客户端发送数据的时候执行的事件
- close 是当客户端离线的时候执行的事件
$server->start() 是启动已创建的实例。
简单聊天室程序
下面我们来写一个简单的例子,一个网页在线聊天室。
代码:
- $server = new Swoole\WebSocket\Server("0.0.0.0", 9523);
- $server->on('open', function (Swoole\WebSocket\Server $server, $request) {
- foreach($server->connections as $key => $fd) {
- $server->push($fd, "欢迎客户端 {$request->fd} 加入聊天!");
- }
- });
- $server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
- foreach($server->connections as $key => $fd) {
- $server->push($fd, "客户端 {$frame->fd}:{$frame->data}");
- }
- });
- $server->on('close', function ($server, $fd) {
- foreach($server->connections as $key => $id) {
- // 即使客户端离线了,但是 connections 里还是有这个客户端的,需要判断一下
- if($fd !== $id) {
- $server->push($id, "欢迎客户端 {$fd} 已退出聊天!");
- }
- }
- });
- $server->start();
介绍
foreach($server->connections as $key => $fd)
这段代码的作用呢,是遍历当前所有客户端连接,作用就是为了给每个客户端都发送一条消息(通过 push 方法)
客户端
我们简单写一个网页对接一下服务端。
代码:
- <span id="status">输入消息</span>
- <input type="text" id="data">
- <button onclick="ws.send(data.value)">发送</button>
- <div id="msg"></div>
- <script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
- <script type="text/javascript">
- var ws;
- ws = new WebSocket("ws://192.168.3.181:9523/");
- ws.onopen = function(event) {
- $("#status").html('已连接成功');
- };
- ws.onmessage = function (event) {
- var msg = event.data + "<br>";
- $("#msg").html(msg + $("#msg").html());
- }
- ws.onclose = function(event) {
- $("#status").html("已经与服务器断开连接,状态:" + this.readyState);
- };
- ws.onerror = function(event) {
- $("#status").html("WebSocket 连接失败!");
- };
- </script>
效果如下

# 关于 SSL 问题
请注意,如果你的网站是 https 的,而 WebSocket 是普通的 ws 协议,那么会导致无法连接,这是浏览器的安全设定。因为 ws 协议是非加密的,你需要使用 wss 协议(即 WebSocket + SSL)。
以下是 Nginx 反向代理 WebSocket 增加 SSL 的相关配置。
代码:
- server {
- # 监听端口 9524
- listen 9524 ssl;
- # SSL 证书的储存位置
- ssl_certificate /path/to/ssl.crt;
- ssl_certificate_key /path/to/ssl.key;
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
- ssl_prefer_server_ciphers on;
- ssl_session_timeout 10m;
- ssl_session_cache builtin:1000 shared:SSL:10m;
- ssl_buffer_size 1400;
- ssl_stapling on;
- ssl_stapling_verify on;
- # 绑定的域名
- server_name example.com;
- include /usr/local/nginx/conf/rewrite/none.conf;
- location / {
- # 反向代理后的后端地址及端口
- proxy_pass http://127.0.0.1:9523;
- proxy_redirect off;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- }
- }
# 相关 Demo
我自己写的论坛程序评论功能已经改成了实时刷新,同时增加了在线人数统计的功能,这一切都是 WebSocket 的功劳。
https://www.zerobbs.net/
感谢阅读,如果这篇文章对你有帮助,欢迎评分。