*workerman的学习和使用,做了个简单聊天室

跑官方demo

常见的协议分3种:

实例一、使用HTTP协议对外提供Web服务

*workerman的学习和使用,做了个简单聊天室_第1张图片

 

注意:

1、浏览器访问不了,是因为端口没开(或关防火墙)

*workerman的学习和使用,做了个简单聊天室_第2张图片

2、如果你使用curl命令来访问的话,要在新开的(当前shell标签右键单击复制ssh渠道)bash中输入指令

3、开发必读里(守护进程才用的到重启。)

 

  > php 文件名 restart #重启

 

实例二、使用WebSocket协议对外提供服务

注意:看图中圈的,客户端的代码要改ip

*workerman的学习和使用,做了个简单聊天室_第3张图片

实例三、直接使用TCP传输数据

*workerman的学习和使用,做了个简单聊天室_第4张图片

*workerman的学习和使用,做了个简单聊天室_第5张图片

 

 

Ctrl + ]  #关闭telnet

在输入quit

注意:如果报错说没有telnet请,可参考https://www.cnblogs.com/ikai/p/7073201.html 安装telnet

 

实例代码,简单聊天室

 

实例二、使用WebSocket协议对外提供服务

建议学习之前先学下websocket。可以参考我这篇博文  

http://blog.csdn.net/qq_33862644/article/details/79551729

首先抛开别的不谈,咱先捋明白业务逻辑,不然看了代码也是懵逼

既然做聊天室(说白了就是类似QQ,一对一聊天)

1、聊天首先要有昵称(花名)

2、必须登录后才能聊天

3、聊天还要找到对方(我们开发肯定是找ip,而不是和聊QQ去根据名字找好友)后在发送消息

 

总思路:客户端发给服务端,服务端处理完,js还要解析显示在html上
1、认证服务器(登录)
    1.1、客户端发送登录消息
    1.2、服务端处理
         使用正则判断,截取用户名
   将登录用户的ip和昵称,保存起来,以后做判断用
         解析完返回消息(客户端标识登录)
2、发消息
    1.1、客户端发送普通消息

        并将客户端发送的消息,显示出来

    1.2、服务端处理

        使用正则判断,截取用户名
        判断发消息的客户端,是否通过服务器认证(是否登录了)

        通过认证的,才可以往客户端发送消息

    1.3、客户端解析服务端返回消息

    将解析好的信息,显示出来

3、广播,显示昵称

    1.1、服务端

   拼接要返回的数据,转成json

        遍历,拿当前和服务器连接的客户端,发消息给客户端

    1.2、客户端

        解析服务端返回的数据,遍历将他显示在昵称列表上

4、单播,一对一聊天 

    1.1、客户端

        通过选择用户昵称

        将消息发给某个用户

    1.2、服务端,通过服务端转发

   解析发过来的数据,取接收方的ip和要发的消息

        判断接收方是否登录了,登录才可发送

   使用接收方的$connection对象发送数据

    1.3、客户端

        解析服务端发过来的数据

        将其在接收方显示出来

5、关闭客户端

    在数组中删除已经登录的用户

6、关闭服务端

    将登录标识置为false

以下是写这个例子我参考的优质博客,大家可以参考

http://blog.csdn.net/github_26672553/article/details/54932788

http://blog.csdn.net/github_26672553/article/details/54946302

http://blog.csdn.net/github_26672553/article/details/55098197

客户端的代码:




    
    Title


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

 

服务端的代码:

 

count = 4;
//2、接收客户端发来的数据
$ws_worker->onMessage = function($connection,$data){
    global $clients;
    //2.1、用户点击的是(链接服务器)验证客户端
    if(preg_match('/^login:(\w{3,20})/i',$data,$result)){
        $ip = $connection->getRemoteIp();       //获取当前客户端IP
        $port = $connection->getRemotePort();   //获取当前客户端端口
        if(!array_key_exists($ip,$clients)){    //判断该ip是否登录过
            //$clients[$ip] = $result[1];         //新登录的ip保存起来
            $clients[$ip.':'.$port] = ['ipp'=>$ip.':'.$port,'name'=>$result[1],'conn'=>$connection]; //广播的话,不止保存昵称,还要保存ip和当前和服务器连接的那个客户端

            //将处理完的信息返回给客户端(给客户端发送任意消息)
            $connection->send('notice:success');
            $connection->send('msg:你好'.$result[1]);
            echo $ip . ':'.$port . '--------' .$result[1] . 'login' . PHP_EOL; //打印看结果

            //一旦有用户登录,就把保存的客户端信息发过去(显示出所有用户)
            //$connection->send('users:'.json_encode($clients));
            //广播(群聊)
            $users = 'users:'.json_encode(array_column($clients,'name','ipp'));   //返回数组中指定的列
            foreach($clients as $ip=>$client){
                //拿当前和服务器连接的那个客户端,发送消息
                $client['conn']->send($users);
            }
        }
    }else if(preg_match('/^msg:(.*?)/isU',$data,$megset)){
        //2.2、处理发来的普通消息
        if(array_key_exists($connection->getRemoteIp(),$clients)){  //判断该ip是否存在,存在就是已经登录的
            echo '用户:' . $connection->getRemoteIp() . '发的消息是' . $megset[1] . PHP_EOL;
            if($megset[1] == 'nihao'){
                $connection->send('msg:nihao'.$clients[$connection->getRemoteIp()]);
            }
            //我认为广播应该在这些,将用户A说的话,显示到页面上,让所有用户都能看见
        }
    }else if(preg_match('/^dian:\<(.*?)\>:(.*?)/isU',$data,$meg)){
        //单播,点对点发消息
        $ipp = $meg[1]; //接收消息用户的ip
        $msg = $meg[2]; //发送的数据
        $name = $clients[$ipp]['name'];    
        echo "
";
        var_dump($name);
        if(array_key_exists($ipp,$clients)){    //接收的ip也登录了,也就是有这个用户
            $clients[$ipp]['conn']->send('dian:'.$msg);
            echo $ipp.'==>'.$msg.PHP_EOL;
        }
    }
};

//客户端关闭
$ws_worker->onClose = function($connection){
  global $clients;
  //echo $clients[$connection->getRemoteIp()].'客户端已断开'.PHP_EOL;
  unset($clients[$connection->getRemoteIp()]);
};

//3、运行
Worker::runAll();

 

其他实例

1、黑/白名单访问

onConnect = function ($connection){
    // IP 白名单验证
    if($connection->getRemoteIP() != '127.0.0.1'){
        $connection->close("IP Address Forbidden");
    }
};
// 接受发送消息
$worker->onMessage = function ($conn,$data){
    $conn->send("Hello World");
};
// 关闭连接
$worker->onClose = function ($connection){
    echo "connection close \n";
};
$worker::runAll();

开启Workerman服务

*workerman的学习和使用,做了个简单聊天室_第6张图片

正确的访问:

非本地地址访问:

2、AsyncTcpConnection类的学习思路:但是代码跑不起来

use Workerman\Worker;
use Workerman\Connection\AsyncTcpConnection;
require_once __DIR__ . '/Workerman/Autoloader.php';

#百度代理的例子 做代理,为什么要改win上的host文件,因为dns先找本地
#浏览器访问百度的时候,首先会向当前服务器(workerman)发起请求,用当前服务器做代理,把百度的数据下载下来,返回给浏览>器
#思路是这么个思路,但是跑不起来

// 创建一个Worker监听2347端口,不使用任何应用层协议
$tcp_worker = new Worker("tcp://0.0.0.0:443");

# 客户端发起链接之后
$tcp_worker->onConnect = function($connection){
        #发起一个百度的链接,因为百度使用的是https,所以端口使用https的端口      
        $connection_baidu = new AsyncTcpConnection('tcp://www.baidu.com:443');  #发起一个异步的tcp链接
        #当百度返回数据之后,use是php的闭包(读取其他函数内部变量,的函数)
        $connection_baidu->onMessage = function($connection_baidu,$data) use ($connection){
                #把客户端的链接给use进来,方便函数体使用,如果不use是无法使用函数外部的变量的
                $connection->send($data); #把数据发给客户端
        };
        #当浏览器发来数据之后,也要把数据转发给百度
        $connection->onMessage = function($connection,$data1) use ($connection_baidu){
                #把数据发给百度
                $connection->send($data1);
        };

        #因为$connection_baidu是异步链接,在链接设置回调完之后还要继续链接
        $connection_baidu->connect();
};

// 运行worker
Worker::runAll();
?>做代理,为什么要改win上的host文件,因为dns先找本地
#浏览器访问百度的时候,首先会向当前服务器(workerman)发起请求,用当前服务器做代理,把百度的数据下载下来,返回给浏览>器
#思路是这么个思路,但是跑不起来

// 创建一个Worker监听2347端口,不使用任何应用层协议
$tcp_worker = new Worker("tcp://0.0.0.0:443");

# 客户端发起链接之后
$tcp_worker->onConnect = function($connection){
        #发起一个百度的链接,因为百度使用的是https,所以端口使用https的端口      
        $connection_baidu = new AsyncTcpConnection('tcp://www.baidu.com:443');  #发起一个异步的tcp链接
        #当百度返回数据之后,use是php的闭包(读取其他函数内部变量,的函数)
        $connection_baidu->onMessage = function($connection_baidu,$data) use ($connection){
                #把客户端的链接给use进来,方便函数体使用,如果不use是无法使用函数外部的变量的
                $connection->send($data); #把数据发给客户端
        };
        #当浏览器发来数据之后,也要把数据转发给百度
        $connection->onMessage = function($connection,$data1) use ($connection_baidu){
                #把数据发给百度
                $connection->send($data1);
        };

        #因为$connection_baidu是异步链接,在链接设置回调完之后还要继续链接
        $connection_baidu->connect();
};

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

 

Timer类的使用

http://www.cnblogs.com/tinywan/p/7420622.html

杂记

 

*workerman的学习和使用,做了个简单聊天室_第7张图片

 

Worker是容器,监听特定端口

当客户端连接到这个端口,会在容器内部产生一个connection对象

Worker容器,可能有很多个connection对象

通过操作connection对象向客户端发送和接收数据等操作

 

有2个connection类:

1、TcpConnection类(连接类的基类);客户端连接上之后自动产生的connection对象;

2、AsyncTcpConnection(是TcpConnection的子类);当我们workerman之后需要访问一个web服务,可以通过这个类异步的发起一个http链接,去链接远程的服务端,异步的通讯;该类是客户端连接其他服务端所用到的类

 

 

 

 

 

你可能感兴趣的:(插件/类库)