workerman 实践 及 不能多人连接的问题

官网:https://www.workerman.net/

手册地址:https://www.workerman.net/doc

追加内容:

请在开发前多读读 开发必读http://doc.workerman.net/development/before-development.html

 

追加内容结束

第一次使用workerman,目标要求实现客户端与服务器1对1的通信。

第一次尝试:

前端js

1
2
3
4
5
6
7
8
9
10
11
12
13
//文档地址
//http://doc.workerman.net/getting-started/simple-example.html
 
// 假设服务端ip为127.0.0.1
ws = new WebSocket("ws://127.0.0.1:2000");
ws.onopen = function() {
    alert("连接成功");
    ws.send('tom');
    alert("给服务端发送一个字符串:tom");
};
ws.onmessage = function(e) {
    alert("收到服务端的消息:" + e.data);
};

 后端 php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//文档地址
//http://doc.workerman.net/getting-started/simple-example.html
 
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';
 
// 注意:这里与上个例子不同,使用的是websocket协议
$ws_worker = new Worker("websocket://0.0.0.0:2000");
 
// 启动4个进程对外提供服务
$ws_worker->count = 4;
 
// 当收到客户端发来的数据后返回hello $data给客户端
$ws_worker->onMessage = function($connection, $data)
{
    // 向客户端发送hello $data
    $connection->send('hello ' . $data);
};
 
// 运行worker
Worker::runAll();

 命令行: 代码部署完毕之后需要在命令行中启动

1
2
3
4
5
6
7
8
9
10
11
// 文档地址
// http://doc.workerman.net/install/start-and-stop.html
 
// 以下运行方式任选一种
// 线上环境需要以守护进程方式启动 并且要加心跳[如果不会请百度]
 
//以debug(调试)方式启动
php start.php start
 
//以daemon(守护进程)方式启动
php start.php start -d

 总结:

1.在测试中发现本方法如果只开启一个进程只能够连接一个客户端,超出一个客户端的连接会出现连接失败,需要等待上一个连接断开之后才能够进行下一个连接[四个进程只能连接四个客户端],但是文档说单个进程最多可以支持5w连接数,手册查找原因【本答案未必准确,百度未找到类似答案 仅作参考】:

追加:

1.不能多人连接是因为php代码出现了报错,如果不能多人连接请解决所有错误

2.不要使用 sleep exit die 函数 导致进程停止或结束

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
// 文档地址
// http://doc.workerman.net/development/before-development.html
 
//三、区分主进程和子进程
 
//有必要注意下代码是运行在主进程还是子进程,一般来说在Worker::runAll();调用前运行的代码都是在主进程运行的,onXXX回调运行的代码都属于子进程。注意写在Worker::runAll();后面的代码永远不会被执行。
 
//例如下面的代码
 
require_once __DIR__ . '/Workerman/Autoloader.php';
use Workerman\Worker;
 
// 运行在主进程
$tcp_worker = new Worker("tcp://0.0.0.0:2347");
// 赋值过程运行在主进程
$tcp_worker->onMessage = function($connection, $data)
{
    // 这部分运行在子进程
    $connection->send('hello ' . $data);
};
 
Worker::runAll();
 
//注意: 不要在主进程中初始化数据库、memcache、redis等连接资源,因为主进程初始化的连接可能会被子进程自动继承(尤其是使用单例的时候),所有进程都持有同一个连接,服务端通过这个连接返回的数据在多个进程上都可读,会导致数据错乱。同样的,如果任何一个进程关闭连接(例如daemon模式运行时主进程会退出导致连接关闭),都导致所有子进程的连接都被一起关闭,并发生不可预知的错误,例如mysql gone away 错误。
 
//推荐在onWorkerStart里面初始化连接资源。

2.当开启多进程的时候,多个客户端进行连接会导致用户发送给服务器的消息会被服务器发送给所有用户

 

第二次尝试:

  第一次尝试由于不支持多人连接,所以百度及文档查找如何进行多人连接,如果进行多人连接,那么就需要使用uid进行标示用户,来给不同的用户发送消息,实现一对一的消息

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
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';
//
$ws_worker = new Worker('websocket://127.0.0.1:2000');
// // 新增加一个属性,用来保存uid到connection的映射(uid是用户id或者客户端唯一标识)
$worker->uidConnections = array();
// 手册说只能一个
$ws_worker->count = 1;
 
// 当收到客户端发来的数据后返回hello $data给客户端
$ws_worker->onMessage = function ($connection, $data) {
    global $ws_worker;
    // 客户端的第一次消息当作获取uid
    // 判断当前客户端是否已经验证,即是否设置了uid
    // 这里只是简单的把 $connection->id 当作他的uid 因为 connection->id 是唯一的
    if (!isset($connection->uid)) {
        $connection->uid = $connection->id;
        $ws_worker->uidConnections[$connection->uid] = $connection;
 
        return $connection->send($connection->uid);
    }
    //获取uid
    list($uid, $message) = explode(':', $data);
    //判断id是否存在 然后发送消息
    if (isset($ws_worker->uidConnections[$uid])) {
        $connection = $ws_worker->uidConnections[$uid];
        $connection->send("自定义消息内容");
    }
};
 
// 运行worker
Worker::runAll();

 

 js

1
2
3
4
5
6
7
8
9
10
11
ws = new WebSocket("ws://127.0.0.1:2000");
var uid = "";
ws.onmessage = function (e) {
            //设置uid
            if(uid == ""){
                uid = e.data;
                return ;
            }
            //实现逻辑代码区域
            //....
}    

 

 总结:

  1.实现了多用户连接[与进程数量无关]

  2.显示单个用户与服务器的一对一的消息

 

posted @   夏秋初  阅读(2416)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示