当前位置: 代码迷 >> 综合 >> swoole-websocket聊天室
  详细解决方案

swoole-websocket聊天室

热度:71   发布时间:2023-12-13 22:38:43.0

服务端:
server.php

<?php/*** Date: 2020/8/28* Time: 3:28 下午*/
class chat
{
    const HOST = '0.0.0.0';//ip地址 0.0.0.0代表接受所有ip的访问const PART = 81;//端口号private $server = null;//单例存放websocket_server对象public function __construct(){
    //实例化swoole_websocket_server并存储在我们Chat类中的属性上,达到单例的设计$this->server = new swoole_websocket_server(self::HOST, self::PART);// 建立连接后进行握手。WebSocket 服务器会自动进行 handshake 握手的过程,如果用户希望自己进行握手处理,可以设置 onHandShake 事件回调函数。
// $this->server->on('handshake', [$this, 'onHandshake']);//监听连接事件$this->server->on('open', [$this, 'onOpen']);//监听接收消息事件$this->server->on('message', [$this, 'onMessage']);//监听关闭事件$this->server->on('close', [$this, 'onClose']);//设置允许访问静态文件$this->server->set(['worker_num'      => 2, //开启2个worker进程'max_request'     => 4, //每个worker进程 max_request设置为4次'task_worker_num' => 4, //开启4个task进程'dispatch_mode'   => 4, //数据包分发策略 - IP分配'daemonize'       => false, //守护进程(true/false)'document_root'         => '/swoole/chat2',//这里传入客户端文件存放地址'enable_static_handler' => true//允许访问静态文件]);//异步防止阻塞当前进程 必须先设置 task_worker_num 必须设置 Server 的 onTask 和 onFinish 事件回调函数。$this->server->on("Task", [$this, 'onTask']);//task 进程中完成时, task 进程会通过 finish() 方法将任务处理的结果发送给 worker 进程。$this->server->on("Finish", [$this, 'onFinish']);//开启服务$this->server->start();}/**** @param \Swoole\Http\Request $request* @param \Swoole\Http\Response $response** @return bool*/public function onHandshake($request, $response){
    // 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: websocketif (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();}/*** 连接成功回调函数---如果系统调用了handshake函数,就不会触发这个** @param Swoole\WebSocket\Server $server* @param Swoole\Http\Request $request** $request 是一个 HTTP 请求对象,包含了客户端发来的握手请求信息* onOpen 事件函数中可以调用 push 向客户端发送数据或者调用 close 关闭连接* onOpen 事件回调是可选的*/public function onOpen($server,$request){
    $this->server->task(['type' => 'online','fd' => $request->fd]);
// foreach ($server->connections as $fd) {
    
// if ($request->fd !== $fd) {
    
// $server->push($fd, json_encode(['no' => $request->fd, 'msg' => '上线了,快来聊天吧!']));
// }
// }}/*** 接收到信息的回调函数** @param Swoole\WebSocket\Server $server* @param Swoole\WebSocket\Frame $frame* 属性 说明$frame->fd 客户端的 socket id,使用 $server->push 推送数据时需要用到$frame->data 数据内容,可以是文本内容也可以是二进制数据,可以通过 opcode 的值来判断$frame->opcode WebSocket 的 OpCode 类型,可以参考 WebSocket 协议标准文档$frame->finish 表示数据帧是否完整,一个 WebSocket 请求可能会分成多个数据帧进行发送(底层已经实现了自动合并数据帧,现在不用担心接收到的数据帧不完整)*/public function onMessage($server, $frame){
    echo $frame->fd . '来了,说:' . $frame->data . PHP_EOL;//打印到我们终端if($frame->data==10){
    $server->push($frame->fd, json_encode(['no' => $frame->fd, 'msg' => '不要发"10",谢谢!']));$this->server->disconnect($frame->fd,403,'不要发"10",谢谢!');}$this->server->task(['type' => 'message','msg' => $frame->data,'fd' =>  $frame->fd]);
// foreach ($server->connections as $fd) {
    
// $server->push($fd, json_encode(['no' => $frame->fd, 'msg' => $frame->data]));
// }}/*** 异步task** @param Swoole\WebSocket\Server $server* @param $task_id //从 0-42 亿的整数,在当前进程内是唯一的* @param $from_id* @param $data*/public function onTask($server, $task_id, $from_id, $data){
    echo "#{
      $server->worker_id} onTask: [PID={
      $server->worker_pid}]: task_id={
      $task_id}: from_id={
      $from_id}".PHP_EOL;$msg = '';switch ($data['type']) {
    case 'online':$msg = '我上线了,快来聊天吧!';break;case 'message':$msg = $data['msg'];break;default:$msg = '这是神马操作!';break;}foreach ($server->connections as $fd) {
    $connectionInfo = $server->connection_info($fd);if ($connectionInfo['websocket_status'] == 3) {
    $server->push($fd, json_encode(['no' => $data['fd'], 'msg' => $msg])); //长度最大不得超过2M}}$server->finish($data);}/*** 此回调函数在 worker 进程被调用,当 worker 进程投递的任务在 task 进程中完成时,* task 进程会通过 Swoole\Server->finish() 方法将任务处理的结果发送给 worker 进程。* @param Swoole\WebSocket\Server $server* @param $task_id* @param $data*/public function onFinish($server,$task_id, $data){
    }/*** 断开连接回调函数** @param Swoole\WebSocket\Server $server* @param int $fdUser*/public function onClose($server, $fdUser){
    
// var_dump($this->server->exist(10));foreach ($server->connections as $fd) {
    if($fd!==$fdUser){
    $server->push($fd, json_encode(['no' => $fdUser, 'msg' => '我走啦!']));}}}
}$obj = new Chat();

客户端
client.html

<!doctype html>
<html>
<head><meta charset="utf-8"><title>swoole-websocket聊天室</title><script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<textarea class="log" style="width: 100%; height: 500px;">
=======swoole-websocket聊天室======
</textarea>
<input type="button" value="连接" onClick="link()">
<input type="button" value="断开" onClick="dis()">
<input type="text" id="text">
<input type="button" value="发送" onClick="send()">
<script>function link(){
     var url='ws://127.0.0.1:81';socket=new WebSocket(url);socket.onopen=function(){
     log1('连接成功')}socket.onmessage=function(msg){
     log(msg.data);console.log(msg);}socket.onclose=function(){
     log1('断开连接')}}function dis(){
     socket.close();socket=null;}function log1(var1) {
     $('.log').append(var1+'\r\n');}function log(var1){
     var v=$.parseJSON(var1)$('.log').append('用户'+v['no']+'说:'+v['msg']+'\r\n');}function send(){
     var text=$('#text').val();socket.send(text);}function send2(){
     var json = JSON.stringify({
     'type':'php','msg':$('#text2').attr('value')})socket.send(json);} </script>
</body>
</html>

启动

php server.php
  相关解决方案