PHP进阶之利用Swoole实现一个简单的WebSocket多人聊天室

其实这个聊天室的DEMO我早都发到Github上了,之前学习Swoole的时候就已经练过手了

之前的同事在群里说他找了一家用Swoole开发的公司,要他做一个简单的聊天室

我最近一直是在找工作的,这就抽空来说一下吧

简单分析一下做聊天室都需要干些什么?

1、首先要有一台WebSocket服务器

2、使用WebSocket协议与服务器进行通信

那什么是WebSocket协议呢?

WebSocketHTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议

WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道,两者之间就直接可以数据互相传送

浏览器通过JavaScript向服务器发出建立WebSocket连接的请求,连接建立以后,客户端和服务器端就可以通过TCP连接直接交换数据

简单的来说,WebSocket只是一个网络通信协议

就像HTTPFTP等都是网络通信的协议,相对于HTTP这种非持久的协议来说,WebSocket是一个持久化网络通信的协议

环境依赖:

这就不用多说了,Linux的服务器,装好PHPSwoole,因为只是一个简单的DEMO,就不存数据了

搭建流程

1、首先有握手信号标识是否成功,成功之后调用回调函数onOpen,这个是可以不设置的,一般用作于欢迎信息之类的

Swoole的文档解释如下:

WebSocket客户端与服务器建立连接并完成握手后会回调此函数

function onOpen(swoole_websocket_server $svr, swoole_http_request $req);
  • $req 是一个Http请求对象,包含了客户端发来的握手请求信息
  • onOpen事件函数中可以调用push向客户端发送数据或者调用close关闭连接
  • onOpen事件回调是可选的

2、当服务器收到来自客户端的数据帧时会回调onMessage函数,客户端发来数据,我们再此函数来将数据广播出去就形成了聊天,经过各种处理形成一个成型的聊天室

Swoole的文档解释如下:

当服务器收到来自客户端的数据帧时会回调此函数

function onMessage(swoole_websocket_server  $server, swoole_websocket_frame $frame);
  • $frame 是swoole_websocket_frame对象,包含了客户端发来的数据帧信息
  • onMessage回调必须被设置,未设置服务器将无法启动
  • 客户端发送的ping帧不会触发onMessage,底层会自动回复pong

3、在onMessage如何发送数据?

WebSocket客户端连接推送数据,长度最大不得超过2M

function swoole_websocket_server->push(int $fd, string $data, int $opcode = 1, bool $finish = true);
  • $fd 客户端连接的ID,如果指定的$fd对应的TCP连接并非websocket客户端,将会发送失败
  • $data 要发送的数据内容
  • $opcode,指定发送数据内容的格式,默认为文本。发送二进制内容$opcode参数需要设置为WEBSOCKET_OPCODE_BINARY
  • 发送成功返回true,发送失败返回false

swoole_websocket_server->push在swoole-1.7.11以上版本可用

代码实现

通过上面的介绍,下面就直接上代码了,在环境目录中间一个名为WebSocket的PHP文件,你也可以换

<?php
// +----------------------------------------------------------------------
// | Swoole聊天室demo
// +----------------------------------------------------------------------
// | IhadPHP [ 学无止境,编码不止,开源为盼 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 - 2018 https://qq52o.me, All rights reserved.
// +----------------------------------------------------------------------
// | Author: 沈唁 <52o@qq52o.cn>
// +----------------------------------------------------------------------

# 定义clientFds数组 保存所有websocket连接
$clientFds = [];

# 创建websocket服务
$server = new swoole_websocket_server("0.0.0.0", 9501);
# 握手成功 触发回调函数
$server->on('open', function (swoole_websocket_server $server, $request) use (&$clientFds) {
   # echo "server: handshake success with fd{$request->fd}\n";
   # 将所有客户端连接标识,握手成功后保存到数组中
   $clientFds[] = $request->fd;
});
# 收到消息 触发回调函数
$server->on('message', function (swoole_websocket_server $server, $frame) use (&$clientFds) {
   # echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
   # $server->push($frame->fd, "this is server");
   # 当有用户发送信息,发送广播通知所有用户
   foreach ($clientFds as $fd) {
      $server->push($fd, $frame->data);
   }
});
# 关闭连接 触发回调函数
$server->on('close', function ($ser, $fd) use (&$clientFds) {
   # echo "client {$fd} closed\n";
   # 关闭会话 销毁标识fd
   # 根据value 去数组中找对应的key
   $res = array_search($fd, $clientFds, true);
   unset($clientFds[$res]);
});
# 启动websocket服务
$server->start();

然后我们在cli下启动服务

php /home/wwwroot/default/WebSocket.php

前端搞一个客户端client链接服务器进行通讯,目前大部分浏览器都支持 WebSocket() 接口,所以就直接写了

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>WebSocket聊天室</title>
</head>
<body>
<div id="main" style="width:600px;height: 200px; overflow: auto;border: solid 2px black;">
</div>
<textarea id="textarea"></textarea>
<br/>
<input type="button" value="发送数据" onclick="send()">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
    var name =prompt("请输入您的昵称","匿名者"); //弹出input框
    // 打开一个 web socket
    var ws = new WebSocket("ws://118.25.224.221:9501");

    ws.onopen = function() {
        console.log("连接成功");
    };

    //收到消息 触发回调
    ws.onmessage = function (evt) {
        var data = evt.data;
        console.log("收到socket服务消息,内容:" + data);
        $('#main').append("<p>" + data + "</p>");
    };

    function send() {
        var data = document.getElementById('textarea').value;
        ws.send(name+ ":"+ data);
    }

    ws.onclose = function() {
        // 关闭 websocket
        console.log("连接已关闭...");
    };
</script>
</body>
</html>

注意替换代码中的ip和端口号,我这边的测试服务器到期了,就不放图片了,代码是没有问题的,我之前都是测试过的,页面比较简陋,就这样吧

测试注意打开控制台~

最后放一个我的项目地址:learn-swoole

沈唁志|一个PHPer的成长之路! 原创文章采用CC BY-NC-SA 4.0协议进行许可,转载请注明:转载自:PHP进阶之利用Swoole实现一个简单的WebSocket多人聊天室

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python专栏

用python来更改小伙伴的windows开机密码,不给10块不给开机

30060
来自专栏Golang语言社区

【Go 语言社区】一个WebSocket的简单Echo例子

一个WebSocket的简单Echo例子:例子代码来自:http://www.websocket.org/echo.html 使用一个文本编辑器,把下面代码复制...

32470
来自专栏皮振伟的专栏

[linux][memory]进程的最大内存使用量的讨论

前言: 一个进程最大能使用多少虚拟内存,能控制的地方还是比想象的多一点。 尤其是IaaS上,一个qemu进程能使用多少虚拟内存,就是对应着虚拟机的物理内存的最大...

2.7K110
来自专栏企鹅号快讯

WebSocket:5分钟从入门到精通

作者:程序猿小卡 https://segmentfault.com/a/1190000012709475 一、内容概览 WebSocket的出现,使得浏览器具备...

27280
来自专栏漫漫前端路

前端安全知识

xss: 跨站脚本攻击(Cross Site Scripting)是最常见和基本的攻击 WEB 网站方法,攻击者通过注入非法的 html 标签或者 javasc...

12620
来自专栏Java编程技术

Druid连接池原理学习

(1)、 如果设置了maxWait或者构造函数参数传入的为true,则创建的ReentrantLock为公平锁,否者为非公平锁 (2)、 如果设置了initi...

2.4K20
来自专栏進无尽的文章

扒虫篇-Bug日志 Ⅲ

解决方法:可能是由于粘贴网页上的代码的时候两行之间的回车引起的,有未识别的回车或者换行,找到,删除掉就 OK了。

15920
来自专栏黄Java的地盘

[翻译]WebSocket协议第一章——Introduction

本文为WebSocket协议的第一章,本文翻译的主要内容为针对整个WebSocket进行一个简单而又全面的介绍。通过这篇文章我们能够对WebSocket有一个整...

10010
来自专栏静默虚空的博客

Elastic 技术栈之 Filebeat

Elastic 技术栈之 Filebeat 简介 Beats 是安装在服务器上的数据中转代理。 Beats 可以将数据直接传输到 Elasticsearch 或...

58070
来自专栏小狼的世界

Log stash学习笔记(一)

Logstash是一款开源的数据收集引擎,具备实时管道处理能力。简单来说,logstash作为数据源与数据存储分析工具之间的桥梁,结合 ElasticSearc...

15830

扫码关注云+社区

领取腾讯云代金券