首页 php框架 ThinkPHP Think-Swoole之WebSocket-Room加入、离开房间和房间消息发送

Think-Swoole之WebSocket-Room加入、离开房间和房间消息发送

Oct 21, 2020 pm 05:17 PM
think-swoole

Think-Swoole之WebSocket-Room加入、离开房间和房间消息发送

Think-Swoole 3.0 中 Websocket 新增了 Room 聊天室功能,它主要用于群发消息,但不同Room之间的消息又是相互隔离的。当我们进入一个聊天室,那么我们的进入、离开以及发送的消息只有这个聊天室的 fd 能接收到。

config.swoole.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

'websocket'  => [

        'enable'        => true,

        'handler'       => Handler::class,

        'parser'        => Parser::class,

        'ping_interval' => 25000,

        'ping_timeout'  => 60000,

        'room'          => [

            'type'  => 'table',

            'table' => [

                'room_rows'   => 4096,

                'room_size'   => 2048,

                'client_rows' => 8192,

                'client_size' => 2048,

            ],

            'redis' => [

                'host'          => '127.0.0.1',

                'port'          => 6379,

                'max_active'    => 3,

                'max_wait_time' => 5,

            ],

        ],

        'listen'        => [],

        'subscribe'     => [],

    ],

登录后复制

其中有 room 配置项,里面的 type 表示使用哪种数据处理方式,下面有两种,“table” 和“redis”,table 是可以直接拿来使用的,而 redis 则需要我们的系统和项目中安装了 redis 扩展。table 是一种高性能、跨进程的内存处理服务,不同进程间可以共享数据。

创建事件

在项目根目录输入如下命令,分别创建加入房间事件、离开房间事件和房间的聊天事件:

1

2

3

php think make:listener WsJoin

php think make:listener WsLeave

php think make:listener RoomTest

登录后复制

然后在 app/event.php 中定义事件:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

[

    ],

    'listen'    => [

        'AppInit'  => [],

        'HttpRun'  => [],

        'HttpEnd'  => [],

        'LogLevel' => [],

        'LogWrite' => [],

        //监听连接,swoole 事件必须以 swoole 开头

        'swoole.websocket.Connect' => [

            app\listener\WsConnect::class

        ],

        //监听关闭

        'swoole.websocket.Close' => [

            \app\listener\WsClose::class

        ],

        //监听 Test 场景

        'swoole.websocket.Test' => [

            \app\listener\WsTest::class

        ],

        //加入房间事件

        'swoole.websocket.Join' => [

            \app\listener\WsJoin::class

        ],

        //离开房间事件

        'swoole.websocket.Leave' => [

            \app\listener\WsLeave::class

        ],

        //处理聊天室消息

        'swoole.websocket.RoomTest' => [

            \app\listener\RoomTest::class

        ],

    ],

    'subscribe' => [

    ],

];

登录后复制

上述的 Join、Leave和RoomTest等名称都是自定义的,要和前端发送消息的场景值对应。

当然,事件定义一样可以在 config/swoole.php 配置文件的 websocket listen 进行配置,具体参考前面文章。

H5 WebSocker 客户端方式连接

wsroot.html

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

<!DOCTYPE HTML>

<html>

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

<button onclick="join()">加入房间</button>

<button onclick="leave()">离开房间</button>

<input type="text" id="message">

<button onclick="send()">发送</button>

<script>

    var ws = new WebSocket("ws://127.0.0.1:9501/?uid=1");

    ws.onopen = function(){

        console.log(&#39;连接成功&#39;);

    }

    //数据返回的解析

    function mycallback(data){

        var start = data.indexOf(&#39;[&#39;) // 第一次出现的位置

        var start1 = data.indexOf(&#39;{&#39;)

        if(start < 0){

            start = start1;

        }

        if(start >= 0 && start1 >= 0){

            start = Math.min(start,start1);

        }

        if(start >= 0){

            console.log(data);

            var json = data.substr(start); //截取

            var json = JSON.parse(json);

            console.log(json);

            // if(json instanceof Array){

            //     window[json[0]](json[1]);

            // }

        }

    }

    function sendfd($message){

        console.log($message)

    }

    function testcallback($message){

        console.log($message)

    }

    function joincallback($message){

        // console.log($message)

        console.log(11);

    }

    function leavecallback($message){

        console.log($message)

    }

    ws.onmessage = function(data){

        // console.log(data.data);

        mycallback(data.data);

    }

    ws.onclose = function(){

        console.log(&#39;连接断开&#39;);

    }

    function join()

{

        var room = prompt(&#39;请输入房间号&#39;);

        ws.send(JSON.stringify([&#39;join&#39;,{

            room:room

        }])); //发送的数据必须是 [&#39;test&#39;,数据] 这种格式

    }

    function leave()

{

        var room = prompt(&#39;请输入要离开的房间号&#39;);

        ws.send(JSON.stringify([&#39;leave&#39;,{

            room:room

        }])); //发送的数据必须是 [&#39;test&#39;,数据] 这种格式

    }

    function send()

{

        var message = document.getElementById(&#39;message&#39;).value;

        var room = prompt(&#39;请输入接收消息的房间号&#39;)

        ws.send(JSON.stringify([&#39;RoomTest&#39;,{

            message:message,

            room:room

        }])); //发送的数据必须是 [&#39;test&#39;,数据] 这种格式

    }

</script>

</body>

</html>

登录后复制

SocketIO 客户端方式连接

ioroomtest.html

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

<!DOCTYPE HTML>

<html>

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

<button onclick="join()">加入房间</button>

<button onclick="leave()">离开房间</button>

<input type="text" id="message">

<button onclick="send()">发送</button>

<script src="./socketio.js"></script>

<script>

    //http 协议

    var socket = io("http://127.0.0.1:9501?uid=1", {transports: [&#39;websocket&#39;]});

    socket.on(&#39;connect&#39;, function(){

        console.log(&#39;connect success&#39;);

    });

    socket.on(&#39;close&#39;,function(){

       console.log(&#39;connect close&#39;)

    });

    //send_fd 为自定义的场景值,和后端对应

    socket.on("sendfd", function (data) {

        console.log(data)

    });

    //testcallback 为自定义的场景值,和后端对应

    socket.on("testcallback", function (data) {

        console.log(data)

    });

    socket.on("joincallback", function (data) {

        console.log(data)

    });

    socket.on("roomtestcallback", function (data) {

        console.log(data)

    });

    function join()

{

        var room = prompt(&#39;请输入房间号&#39;);

        socket.emit(&#39;join&#39;,{

            room : room

        });

    }

    function leave()

{

        var room = prompt(&#39;请输入要离开的房间号&#39;);

        socket.emit(&#39;leave&#39;,{

            room : room

        });

    }

    function send()

{

        var message = document.getElementById(&#39;message&#39;).value;

        var room = prompt(&#39;请输入接收消息的房间号&#39;)

        socket.emit(&#39;RoomTest&#39;,{

            message : message,

            room : room

        });

    }

</script>

</body>

</html>

登录后复制

页面中,join()、leave()、和send() 函数中定义的场景值分别是 join、leave和RoomTest,我们在 app/leave.php 中定义了这些场景值对应的事件,因此分别触发 WsJoin.php、WsLeave.php 和 RoomTest.php 事件。

后端事件编写

app/listener/WsJoin.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

<?php

declare (strict_types = 1);

namespace app\listener;

class WsJoin

{

    /**

     * 事件监听处理

     *

     * @return mixed

     */

    public function handle($event)

{

        $ws = app(&#39;think\swoole\Websocket&#39;);

        $roomobj = app(&#39;think\swoole\websocket\Room&#39;);

        //当前客户端加入指定 Room

        $ws -> join($event[&#39;room&#39;]);

        //同时加入多个房间

//        $ws -> join([&#39;room1&#39;,&#39;room2&#39;]);

        //指定客户端加入指定 room

//        $ws -> setSender(2) -> join($event[&#39;room&#39;]);

        //获取当前房间所有的 fd

        $getAllFdInRoom = $roomobj -> getClients($event[&#39;room&#39;]);

        //获取指定 fd 加入哪些房间

        $getAllRoom = $roomobj -> getRooms($ws -> getSender());

        var_dump(&#39;当前房间所有 fd:&#39;,$getAllFdInRoom);

        var_dump(&#39;当前 fd 加入的所有房间:&#39;,$getAllRoom);

        var_dump(&#39;当前请求数据:&#39;,$event);

        $ws -> emit(&#39;joincallback&#39;,&#39;房间加入成功&#39;);

    }

}

登录后复制

app/listener/WsLeave.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<?php

declare (strict_types = 1);

namespace app\listener;

class WsLeave

{

    /**

     * 事件监听处理

     *

     * @return mixed

     */

    public function handle($event)

{

        $ws = app(&#39;think\swoole\Websocket&#39;);

        $roomobj = app(&#39;think\swoole\websocket\Room&#39;);

        // 当前客户端离开指定 room

        $ws -> leave($event[&#39;room&#39;]);

        // 同时离开多个 room

//        $ws -> leave([&#39;one&#39;,&#39;two&#39;]);

        // 指定客户端离开指定 room

//        $ws -> setSender(2) -> leave($event[&#39;room&#39;]);

        // 获取指定 room 中的所有客户端 fd

        $getAllFdInRoom = $roomobj -> getClients($event[&#39;room&#39;]);

        var_dump(&#39;当前房间还剩 fd:&#39;,$getAllFdInRoom);

        $ws -> emit(&#39;leavecallback&#39;,&#39;房间离开成功&#39;);

    }

}

登录后复制

app/listener/RoomTest.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<?php

declare (strict_types = 1);

namespace app\listener;

class RoomTest

{

    /**

     * 事件监听处理

     *

     * @return mixed

     */

    public function handle($event)

{

        var_dump($event);

        $ws = app(&#39;think\swoole\Websocket&#39;);

        //给指定的 room 内所有 fd 发送消息,包括当前客户端,当前客户端没有加入该 room 也可发送

        $ws -> to($event[&#39;room&#39;]) -> emit(&#39;roomtestcallback&#39;,$event[&#39;message&#39;]);

        //指定多个 room 发送消息

        //$ws -> to([&#39;one&#39;,&#39;two&#39;]) -> emit(&#39;客户端场景值&#39;,$event[&#39;message&#39;]);

    }

}

登录后复制

以上分别是前端 HTML 页面和后端的加入房间、离开房间和房间聊天事件代码,下面开始测试。

首先在项目根目录开启 Think-Swoole 服务。

浏览器访问 wsroot.html 或者 ioroomtest.html 页面,可以打开多个标签,模拟多个客户端,我们先打开三个,连接成功后,fd 分别为1、2、3,我们让 fd 1 和 2 的客户端都加入“one”,房间,fd 为 3 的客户端加入 “two” 房间,由于我们在 WsJoin.php 加入房间事件中打印了用户加入房间所有 fd,和该用户所加入的所有房间名称,这些信息会打印在命令行中,最后会发送给当前客户端聊天场景值和“加入房间成功”信息给客户端,在浏览器控制台可查看。

加入房间后,用 fd 为 1 的客户端在页面的输入框输入要发送的消息,点击发送后,输入要发送的房间名称为“one”,然后,消息就发送到“one”房间,只有“one”房间的所有客户端(fd 为1、2)能收到消息。

现在让 fd 为 2 的客户端离开 “one” 房间,由于在 WsLeave.php 离开房间事件中,我们打印了离开后剩余 fd,信息会出现在命令行中,可见“one”房间只剩下 fd 1 了,fd 1 发送信息,fd 2 就收不到了。

关于 WebSocket-Room 的其他功能,都已经在上述代码中注释了,需要可打开进行测试。

H5 WebSocket 和 SocketIO 对于消息的处理,上篇文章已经演示过了,前者对于服务端返回的消息需要手动解析才能使用,后者会根据消息的场景值接收消息,并做过处理可以直接使用。

以上是Think-Swoole之WebSocket-Room加入、离开房间和房间消息发送的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

TP6 Think-Swoole RPC服务的性能优化与调试 TP6 Think-Swoole RPC服务的性能优化与调试 Oct 12, 2023 am 11:16 AM

TP6Think-SwooleRPC服务的性能优化与调试一、引言随着互联网的迅猛发展,分布式计算已经成为了现代软件开发中不可或缺的一部分。在分布式计算中,RPC(RemoteProcedureCall,远程过程调用)是一种常用的通信机制,通过它可以实现跨网络的方法调用。Think-Swoole作为一个高性能的PHP框架,可以很好地支持RPC服务。但是

TP6 Think-Swoole RPC服务的高可扩展性与分布式部署 TP6 Think-Swoole RPC服务的高可扩展性与分布式部署 Oct 12, 2023 am 11:07 AM

TP6(ThinkPHP6)是一款基于PHP的开源框架,具有高可扩展性与分布式部署的特点。本文将介绍如何使用TP6配合Swoole扩展,搭建一个具备高可扩展性的RPC服务,并给出具体的代码示例。首先,我们需要安装TP6和Swoole扩展。在命令行中执行以下命令:composerrequiretopthink/thinkpeclinstallswo

TP6 Think-Swoole RPC服务的数据加密与身份认证机制 TP6 Think-Swoole RPC服务的数据加密与身份认证机制 Oct 12, 2023 am 11:29 AM

TP6Think-SwooleRPC服务的数据加密与身份认证机制随着互联网的快速发展,越来越多的应用程序需要进行远程调用,以实现不同模块之间的数据交互和功能调用。在这样的背景下,RPC(RemoteProcedureCall)就成了一种重要的通信方式。TP6Think-Swoole框架可以实现高性能的RPC服务,本文将介绍如何通过数据加密与身份认证

TP6 Think-Swoole的RPC服务与消息队列的集成与应用 TP6 Think-Swoole的RPC服务与消息队列的集成与应用 Oct 12, 2023 am 11:37 AM

TP6Think-Swoole的RPC服务与消息队列的集成与应用在现代软件开发中,RPC服务(RemoteProcedureCall)和消息队列是常见的技术手段,用于实现分布式系统中的服务调用和异步消息处理。在TP6框架中集成Think-Swoole组件,可以轻松实现RPC服务和消息队列的功能,并且提供了简洁的代码示例,方便开发者理解和应用。一、RPC

TP6 Think-Swoole RPC服务的高并发请求处理与调度 TP6 Think-Swoole RPC服务的高并发请求处理与调度 Oct 12, 2023 pm 12:33 PM

TP6Think-SwooleRPC服务的高并发请求处理与调度随着互联网技术的不断发展,网络应用的并发请求处理和调度成为了一个重要的挑战。在TP6框架中,使用Think-Swoole扩展可以实现RPC(RemoteProcedureCall)服务的高并发请求处理与调度。本文将介绍如何在TP6框架中搭建一个基于Think-Swoole的RPC服务,并提

TP6 Think-Swoole RPC服务的安全防护与授权验证 TP6 Think-Swoole RPC服务的安全防护与授权验证 Oct 12, 2023 pm 01:15 PM

TP6Think-SwooleRPC服务的安全防护与授权验证随着云计算和微服务的兴起,远程过程调用(RPC)成为了开发者们日常工作中必不可少的一部分。在开发RPC服务时,安全防护和授权验证是非常重要的,以确保只有合法的请求可以访问和调用服务。本文将介绍如何在TP6Think-Swoole框架中实现RPC服务的安全防护和授权验证。一、RPC服务的基本概念

TP6 Think-Swoole构建的RPC服务与微服务架构实践案例 TP6 Think-Swoole构建的RPC服务与微服务架构实践案例 Oct 12, 2023 pm 12:04 PM

TP6Think-Swoole构建的RPC服务与微服务架构实践案例引言:随着互联网的快速发展以及业务规模的扩大,传统的单体架构已经无法满足大规模业务场景的需求。因此,微服务架构应运而生。在微服务架构中,RPC(RemoteProcedureCall)服务是实现服务间通信的一种重要方式。通过RPC服务,各个微服务之间可以方便、高效地互相调用。在本篇文章中

TP6 Think-Swoole RPC服务的性能测试与性能调优 TP6 Think-Swoole RPC服务的性能测试与性能调优 Oct 12, 2023 pm 02:19 PM

TP6Think-SwooleRPC服务的性能测试与性能调优一、引言随着互联网的高速发展,分布式系统的应用越来越广泛。而在分布式系统中,RPC(远程过程调用)是一种常见的通信机制,它可以让不同节点的服务相互调用,实现分布式系统的协同工作。在TP6框架中,Think-Swoole作为一种高性能的Swoole驱动,提供了方便的RPC服务支持。本文主要介绍了T

See all articles