WorkerMan学习篇:websocket+workerman聊天功能(三):点对点发送消息模拟(亲测可用_准备尝试着做客服接口)

1.WorkerMan学习篇:准备和热身
2.WorkerMan学习篇:连接mysql时到底发生了什么鬼
3. WorkerMan学习篇:websocket+workerman聊天功能设计(一):简单认证
4.WorkerMan学习篇:websocket+workerman聊天功能(二):同步在线用户列表

上节课我们已经完成了同步在线用户列表,因为我们是使用IP作为一个唯一判断标志,所以我们的一台电脑只能登录一个用户:

    if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ //代表是客户端认证

        $ip = $connection->getRemoteIp();
        if(!array_key_exists($ip,$clients)){ //必须是之前没有注册过
//....
//....

 

实际上,可以在一台电脑上,同时几个客户端来登录,只要保证这个key不唯一就行了,比如说可以拼接上一个端口:

 //存储新登录用户的数据
$clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection];

 

WorkerMan学习篇:websocket+workerman聊天功能(三):点对点发送消息模拟(亲测可用_准备尝试着做客服接口)_第1张图片
server端全部代码:

count = 4;

/**
 * 同步登录用户列表
 */
function syncUsers()
{
    global $clients;

    $users = 'users:'.json_encode(array_column($clients,'name','ipp')); //准备要广播的数据
    foreach($clients as $ip=>$client){
        $client['conn']->send($users);
    }
}

// 当收到客户端发来的数据后
$ws_worker->onMessage = function($connection, $data)
{
    //这里用global的原因是:php是有作用域的,我们是在onMessage这个回调还是里操作外面的数组
    //想要改变作用域外面的数组,就global一下
    global $clients;

    //验证客户端用户名在3-20个字符
    if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ //代表是客户端认证

        $ip = $connection->getRemoteIp();
        $port = $connection->getRemotePort();

        if(!array_key_exists($ip.':'.$port, $clients)){ //必须是之前没有注册过

            //存储新登录用户的数据
            $clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection];

            // 向客户端发送数据
            $connection->send('notice:success'); //验证成功消息
            $connection->send('msg:welcome '.$result[1]); //普通消息
            echo $ip .':'.$port.'==>'.$result[1] .'==>login' . PHP_EOL; //这是为了演示,控制台打印信息

            //有新用户登录
            //需要同步登录用户数据
            syncUsers();
        }

    }elseif(preg_match('/^msg:(.*?)/isU',$data,$msgset)){ //代表是客户端发送的普通消息

        if(array_key_exists($connection->getRemoteIp(),$clients)){ //必须是之前验证通过的客户端
            echo 'get msg:' . $msgset[1] .PHP_EOL; //这是为了演示,控制台打印信息
            if($msgset[1] == 'nihao'){
                //如果收到'nihao',就给客户端发送'nihao 用户名'
                //给客户端发送普通消息
                $connection->send('msg:nihao '.$clients[$connection->getRemoteIp()]);
            }
        }
    }

    // 设置连接的onClose回调
    $connection->onClose = function($connection) //客户端主动关闭
    {
        global $clients;
        unset($clients[$connection->getRemoteIp().':'.$connection->getRemotePort()]);

        //客户端关闭
        //即退出登录,也需要更新用户列表数据
        syncUsers();

        echo "connection closed\n";
    };
};

// 运行worker
Worker::runAll();

 

点对点聊天简单设计

听起来好像是:利用websocket客户端直接向其他宇宙中的websocket发送消息。

实际上是:
客户端html——>workerman监听9090端口(自己有个协议,服务端来中转)——–>客户端html

1.客户端构建发送消息,遵守一定的协议

var listusers = document.getElementById('listusers');
var toUserIPP = listusers.options[listusers.selectedIndex].value; //发给用户的ip和端口
var toUserName = listusers.options[listusers.selectedIndex].text; //发给用户的昵称
socket.send('chat:<'+toUserIPP+'>:'+msg);

 

客户端最终发送一条chat:<10.211.55.2:50543>:message 这样的消息给服务端。
服务端判断并根据ip+端口发送给对应的用户:

if (preg_match('/^chat:\<(.*?)\>:(.*?)/isU',$data,$msgset)){
    $ipp = $msgset[1];
    $msg = $msgset[2];

    if (array_key_exists($ipp,$clients)){ //如果有这个用户
        //就发送普通消息
        $clients[$ipp]['conn']->send('msg:'.$msg);

        echo $ipp.'==>'.$msg.PHP_EOL;
    }
}

 

 

WorkerMan学习篇:websocket+workerman聊天功能(三):点对点发送消息模拟(亲测可用_准备尝试着做客服接口)_第2张图片

服务端全部代码:

count = 4;

/**
 * 同步登录用户列表
 */
function syncUsers()
{
    global $clients;

    $users = 'users:'.json_encode(array_column($clients,'name','ipp')); //准备要广播的数据
    foreach($clients as $ip=>$client){
        $client['conn']->send($users);
    }
}

// 当收到客户端发来的数据后
$ws_worker->onMessage = function($connection, $data)
{
    //这里用global的原因是:php是有作用域的,我们是在onMessage这个回调还是里操作外面的数组
    //想要改变作用域外面的数组,就global一下
    global $clients;

    //验证客户端用户名在3-20个字符
    if(preg_match('/^login:(\w{3,20})/i',$data,$result)){ //代表是客户端认证

        $ip = $connection->getRemoteIp();
        $port = $connection->getRemotePort();

        if(!array_key_exists($ip.':'.$port, $clients)){ //必须是之前没有注册过

            //存储新登录用户的数据
            $clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection];

            // 向客户端发送数据
            $connection->send('notice:success'); //验证成功消息
            $connection->send('msg:welcome '.$result[1]); //普通消息
            echo $ip .':'.$port.'==>'.$result[1] .'==>login' . PHP_EOL; //这是为了演示,控制台打印信息

            //有新用户登录
            //需要同步登录用户数据
            syncUsers();
        }

    }elseif(preg_match('/^msg:(.*?)/isU',$data,$msgset)){ //代表是客户端发送的普通消息

        if(array_key_exists($connection->getRemoteIp(),$clients)){ //必须是之前验证通过的客户端
            echo 'get msg:' . $msgset[1] .PHP_EOL; //这是为了演示,控制台打印信息
            if($msgset[1] == 'nihao'){
                //如果收到'nihao',就给客户端发送'nihao 用户名'
                //给客户端发送普通消息
                $connection->send('msg:nihao '.$clients[$connection->getRemoteIp()]);
            }
        }
    }elseif (preg_match('/^chat:\<(.*?)\>:(.*?)/isU',$data,$msgset)){
        $ipp = $msgset[1];
        $msg = $msgset[2];

        if (array_key_exists($ipp,$clients)){ //如果有这个用户
            //就发送普通消息
            $clients[$ipp]['conn']->send('msg:'.$msg);

            echo $ipp.'==>'.$msg.PHP_EOL;
        }
    }

    // 设置连接的onClose回调
    $connection->onClose = function($connection) //客户端主动关闭
    {
        global $clients;
        unset($clients[$connection->getRemoteIp().':'.$connection->getRemotePort()]);

        //客户端关闭
        //即退出登录,也需要更新用户列表数据
        syncUsers();

        echo "connection closed\n";
    };
};

// 运行worker
Worker::runAll();

 

客户端全部代码:




    
    WebSocket_client
    


    
所有用户:
你的昵称:
回复内容:

 

你可能感兴趣的:(php)