简单的swoole聊天室

字号+ 编辑: 国内TP粉 修订: 种花家 来源: 孙文正 2023-09-12 我要说两句(0)

转自segmentfault

我看了看官网的demo,觉得看起来很简单嘛,

<?php


$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";//$request->fd 是客户端id
});

$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"); // $frame->fd 是客户端id,$frame->data是客户端发送的数据
    // 服务端向客户端发送数据是用 $server->push( '客户端id' , '内容')
});

$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});
$server->start();



我就是喜欢这种简单易懂的demo,每行代码意思一看就明白

服务端有了,我找点客户端的js代码
火狐的MDN

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset="UTF-8">
    <script type="text/javascript">
    var exampleSocket = new WebSocket("ws://0.0.0.0:9501");
    exampleSocket.onopen = function (event) { exampleSocket.send("亲爱的服务器!我连上你啦!");
    };
    exampleSocket.onmessage = function (event) {
        console.log(event.data);
    }
    </script>
</head>
<body>
    <input type="text" id="content"/>
    <button onclick="exampleSocket.send( document.getElementById('content').value )">发送</button>
</body></html>

最后命令行运行php文件,之后浏览器打开html文件,
F12打开调试界面看console,ok,没有问题

这个时候我突然想到一个事情,因为我做多进程的那个教程里,在主进程中会将所有的子进程的句柄存起来,以后进行进程间通讯用。
那么 我将所有的客户端的链接存起来存成数组,每当一个客户端发送消息时,我就遍历这个客户端数组,将消息群发一遍,不久实现了聊天室了吗?
然后就,服务端代码成了这个样子

<?php
$map = array();//客户端集合$server = new swoole_websocket_server("0.0.0.0", 9501);
$server->on('open', function (swoole_websocket_server $server, $request) {
    global $map;//客户端集合 $map[$request->fd] = $request->fd; // 首次连上时存起来
});

$server->on('message', function (swoole_websocket_server $server, $frame) {
    global $map; // 客户端集合
    $data = $frame->data; foreach($map as $fd){
        $server->push($fd , $data); // 循环广播
    }
});

$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});

$server->start();

哈哈 , 我觉得这样就大功告成了,结果发现自己是 图样图森破
大家可以自己试试,运行php后 , 浏览器打开两个页面,看看console.log的内容是什么

运行良好,可是并没有实现我们说的那种聊天效果。
找找原因吧。
我第一反映看看$map里面是什么,就输出看看,结果发现这个map里面只有一个元素。
唉,不对啊,我这是全局变量,难道不应该是有几个客户端链接,就有几个元素吗?
这是怎么回事啊,竟然没有保存到所有客户端id?

到了这一步,我解决不了map变量的这个问题了,然后我就想看看那个fd是什么东西,
老规矩 var_dump输出 , 发现fd就是 int类型的数字,并且是自增的
这好办了,不就是数字嘛

于是呼,我就这样做
变量存不了,我搞不定,我存文本里嘛。
最终版 websocket.php

<?php
$server = new swoole_websocket_server("0.0.0.0", 9501);
$server->on('open', function (swoole_websocket_server $server, $request) {
    file_put_contents( __DIR__ .'/log.txt' , $request->fd);
});

$server->on('message', function (swoole_websocket_server $server, $frame) {

    global $client;
    $data = $frame->data;
    // 内存广播
/*
    foreach($server->connections as $fd) {
        $server->push($fd, $data);
    }
*/

    $m = file_get_contents( __DIR__ .'/log.txt');
    for ($i=1 ; $i<= $m ; $i++) {
        echo PHP_EOL . ' i is ' . $i . ' data is '.$data . ' m = ' . $m;  $server->push($i, $data );
    }

});

$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});

$server->start();

再次打开html文件,多个页面进行输入观察,ok,可以了。

当然,作为聊天室,我这写的也过于简陋了,界面大家自己可以写的好看一些(因为我懒的写界面)
还有,每次的发送聊天的记录,应该存起来,这样,如果有新的连接连过来的时候,先把以前的聊天记录发过去,这样,我想体验更好一些

 

阅完此文,您的感想如何?
  • 有用

    0

  • 没用

    0

  • 开心

    0

  • 愤怒

    0

  • 可怜

    0

1.如文章侵犯了您的版权,请发邮件通知本站,该文章将在24小时内删除;
2.本站标注原创的文章,转发时烦请注明来源;
3.Q群: 2702237 13835667

相关课文
  • mac开发接入微信公众号接口返回报错 cURL error 56: SSLRead() return error -9806

  • PHP的换行符是什么

  • pecl安装程序时报错Array and string offset access syntax with curly braces is no longer supported

  • 由于商家传入的H5交易参数有误,该笔交易暂时无法完成,请联系商家解决

我要说说
网上嘉宾点评