Swoole简单入门教程聊天系统

news/2024/7/2 23:05:32

Swoole可以让PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。

一、使用Swoole实现在线聊天
建立服务端主程序

准备工作就绪后,我们开始来撸代码。

首先在项目目录:src/app/ 下建立​​Chat.php​​,用作Swoole服务端主程序。

Chat.php文件的主体结构是这样的:

 
namespace Shanhubei\Swoole;
use swoole_websocket_server;
class Chat
{
    protected $ws;
    protected $host = '0.0.0.0';
    protected $port = 9504;
    // 进程名称
    protected $taskName = 'swooleChat';
    // PID路径
    protected $pidFile = '/run/swooleChat.pid';
    // 设置运行时参数
    protected $options = [
        'worker_num' => 4, //worker进程数,一般设置为CPU数的1-4倍  
        'daemonize' => true, //启用守护进程
        'log_file' => '/data/logs/chatswoole.log', //指定swoole错误日志文件
        'log_level' => 3, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR
        'dispatch_mode' => 1, //数据包分发策略,1-轮询模式
    ];
 
 
    public function __construct($options = [])
    {
        $this->ws = new swoole_websocket_server($this->host, $this->port);
 
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
        $this->ws->set($this->options);
 
        $this->ws->on("open", [$this, 'onOpen']);
        $this->ws->on("message", [$this, 'onMessage']);
        $this->ws->on("close", [$this, 'onClose']);
    }
 
    public function start()
    {
        // Run worker
        $this->ws->start();
    }
 
    public function onOpen(swoole_websocket_server $ws, $request)
    {
        // 设置进程名
        cli_set_process_title($this->taskName);
        //记录进程id,脚本实现自动重启
        $pid = "{$ws->master_pid}\n{$ws->manager_pid}";
        file_put_contents($this->pidFile, $pid);
 
        echo "server: handshake success with fd{$request->fd}\n";
    }
 
    public function onMessage(swoole_websocket_server $ws, $frame)
    {
        //$ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));
        $connets = $ws->connections;
        echo count($connets)."\n";
        echo $frame->data. "\n";
        if ($frame->data == '美女') {
            $mmpic = [
                'http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg',
                'http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg',
                'http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg'
            ];
            $picKey = array_rand($mmpic);
            $ws->push($frame->fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);
        } else {
            $ws->push($frame->fd, $this->reply($frame->data));
        }
        
    }
 
    public function onClose($ws, $fid)
    {
        echo "client {$fid} closed\n";
        foreach ($ws->connections as $fd) {
            $ws->push($fd, $fid. '已离开!');
        }
    }
 
    private function reply($str) {
        $str = mb_strtolower($str);
        switch ($str) {
            case 'hello':
                $res = 'Hello, Friend.';
                break;
 
            case 'fuck':
                $res = 'Fuck bitch.';
          
                break;
            case 'ping':
                $res = 'PONG.';
                break;
            case 'time':
                $res = date('H:i:s');
                break;
            
            default:
                $res = $str;
                break;
        }
        return $res;
    }
}

我们需要往​​onMessage()​​方法里填代码。在这里,服务端接收客户端消息,并作出相应动作。Websocket可以向客户端发送字符串、二进制等形式消息。

public function onMessage(swoole_websocket_server $ws, $frame)
    {
        //$ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));
     if ($frame->data == '美女') {
            $mmpic = [
                'http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg',
                'http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg',
                'http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg'
            ];
            $picKey = array_rand($mmpic); //随机返回一张图片
            $ws->push($frame->fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);
        } else {
            $ws->push($frame->fd, $this->reply($frame->data));
        }
    }
 
    private function reply($str) {
        $str = mb_strtolower($str);
        switch ($str) {
            case 'hello':
                $res = 'Hello, Friend.';
                break;
 
            case 'fuck':
                $res = 'Fuck bitch.';
                break;
            case 'ping':
                $res = 'PONG.';
                break;
            case 'time':
                $res = date('H:i:s');
                break;
            
            default:
                $res = $str;
                break;
        }
        return $res;
    }

将上面代码加入到Chat.php中,用来处理接收消息并响应回复。响应回复的内容可以根据实际情况修改,本代码只是用来演示。

启动服务端

在public/目录下建立chatServer.php,代码如下:

require dirname(__DIR__) . '/vendor/autoload.php';
 
use Shanhubei\Swoole\Chat;
 
$opt = [
    'daemonize' => true
];
$ws = new Chat($opt);
$ws->start();

然后运行以下代码启动服务端:​​php chatServer.php​​ 如果一切正常,你可以netstat -lntp看一下,系统会监听进程名为swooleChat,端口为9504的服务。

启动客户端

我们使用HTML5的websocket客户端来连接服务端,本地建立wsClient.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
    <title>Client</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="css/chat.css">
</head>
<body>
    <div id="chat-wrap">
        <div id="result"></div>
        <ul class="chat-thread">
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>Are we meeting today?</p></li>
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li>
            <li class="me"><img class="head" src="images/head1.jpg" alt=""><p>一部分保持在行尾,另一部分换到下一行。</p></li>
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li>
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li>
        </ul>
        
    </div>
    <div class="send">
        <form action="">
          <input type="text" class="form-control" id="m" autocomplete="off" placeholder="请输入内容">
          <button type="submit" class="btn btn-info">发送</button>
        </form>
    </div>
<!-- <div>
    <div id="result"></div>
    <form class="form-inline" action="">
      <div class="form-group">
        <input type="text" class="form-control" id="m" autocomplete="off" placeholder="请输入内容">
      </div>
      <button type="submit" class="btn btn-info">发送</button>
    </form>
</div> -->
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script>
if ("WebSocket" in window) {
    var ws = new WebSocket("ws://192.168.3.105:9504");
 
    var result = document.querySelector('#result');
 
    var chatthread = document.querySelector('.chat-thread');
    chatthread.scrollTop = chatthread.scrollHeight;
 
    ws.onopen = function() {
        result.innerHTML = '已连接上!';
        $('#result').show().html('已连接上!').fadeOut(1500);
        console.log('已连接上!');
    }
 
    document.querySelector('form').onsubmit = function(e) {
        var msg = document.querySelector('#m').value;
        ws.send(msg);
        $('.chat-thread').append('<li class="me"><img class="head" src="images/head1.jpg" alt=""><p>'+msg+'</p></li>');
        chatthread.scrollTop = chatthread.scrollHeight;
        document.querySelector('#m').value = '';
        return false;
    }
    ws.onmessage = function(e) {
        if(e.data instanceof Blob) {
            // var img = document.createElement("img");
            // img.src = window.URL.createObjectURL(e.data);
            // result.appendChild(img);
            // var d = window.URL.createObjectURL(e.data);
            // console.log(d);
            var img = '<img src="'+window.URL.createObjectURL(e.data)+'" width="180"/>';
            $('.chat-thread').append('<li class="you"><img class="head" src="images/head1.jpg" alt=""><p>'+img+'</p></li>');
        }else {
            // var p = document.createElement("p");
            // p.innerHTML = e.data;
            // result.appendChild(p);
            $('.chat-thread').append('<li class="you"><img class="head" src="images/head1.jpg" alt=""><p>'+e.data+'</p></li>');
        }
        chatthread.scrollTop = chatthread.scrollHeight;
    }
    ws.onclose = function() {
        console.log('连接已关闭!');
    }
} else {
    alert('您的浏览器不支持 WebSocket!');
}
</script>
</body>
</html>

然后用浏览器打开wsClient.html,你可以看到一个聊天窗口,一开始会提示连接成功,然后你可以在输入框中输入你想说的话,如“美女”等等。


http://lihuaxi.xjx100.cn/news/2157326.html

相关文章

利用Java实现每周二上午十点定时调用接口的方法

摘要&#xff1a; 在软件开发中&#xff0c;定时任务是一项常见的需求&#xff0c;特别是需要定期执行一些特定操作的场景。本文将介绍如何利用Java编程语言实现每周二上午十点定时调用接口的功能。通过使用Java中的定时任务调度工具&#xff0c;我们可以轻松地实现这一功能&am…

C++和C中的struct 和public有什么区别

在C和C语言中&#xff0c;struct 和 public 关键字分别具有不同的作用&#xff0c;它们的主要区别在于以下方面&#xff1a; struct&#xff08;结构体&#xff09;&#xff1a; 在C语言中&#xff0c;struct 用于定义自定义的复合数据类型&#xff0c;可以包含不同类型的成员变…

AI时代:程序员不是失业,而是逆袭的开始

&#x1f30c;引言&#xff1a; 在AI的浪潮之下&#xff0c;一个挑战性的问题逐渐浮出水面——AI的崛起是否意味着程序员的失业&#xff1f;这个问题不仅激发了技术界的广泛讨论&#xff0c;也触动了每一位程序员的心弦。然而&#xff0c;在这背后&#xff0c;我们应该看到的是…

简单使用Linux printf 将十进制转换为十六进制

在开发和排查问题过程中&#xff0c;有时我们需要做一些进制的转换&#xff0c;以下是一些快速的小技巧&#xff1a; 下面的是 十进制转换为十六进制&#xff1a; ❯ printf "0x%x\n" 100 0x64 还可以把 十六进制转为十进制&#xff1a; ❯ printf "%d\n&q…

SpringMVC转发和重定向

转发和重定向 1. View Resolver Spring MVC 中的视图解析器&#xff08;View Resolver&#xff09;负责解析视图。可以通过在配置文件中定义一个 View Resolver 来配置视图解析器&#xff1a; 配置文件版&#xff1a;spring-web.xml <!-- for jsp --> <bean class&q…

MySQL View 视图

拓展阅读 MySQL View MySQL truncate table 与 delete 清空表的区别和坑 MySQL Ruler mysql 日常开发规范 MySQL datetime timestamp 以及如何自动更新&#xff0c;如何实现范围查询 MySQL 06 mysql 如何实现类似 oracle 的 merge into MySQL 05 MySQL入门教程&#xff0…

Javascript - 你在项目中是如何使用闭包的

难度级别:中高级及以上 提问概率:80% 很多初级开发者其实在日常工作中,很少有使用闭包的机会,但这却是一个非常高频的考点,因为对闭包不是特别了解,使用又少,久而久之,就觉得闭包是一个难点。在Javascript中,一个普通方法在执行完毕后…

C语言文件操作2

1.二进制读写函数 在上一章我们介绍了字符读写函数、文本读写函数和格式化输入输出函数&#xff0c;这张我们继续为大家介绍剩下的一组读写函数——二进制读写函数&#xff1a;fread函数和fwrite函数。 ⚀fread函数 &#x1f7e1;函数作用 以二进制的方式从指定流中读取数据 …