Heim  >  Artikel  >  PHP-Framework  >  So implementieren Sie einen Online-Chat mit Workerman

So implementieren Sie einen Online-Chat mit Workerman

尚
nach vorne
2019-12-26 17:00:533267Durchsuche

So implementieren Sie einen Online-Chat mit Workerman

workerman ist ein in PHP geschriebener Kommunikationsdienst. Frühere Projekte haben es für Datenschnittstellendienste verwendet

Dieses Mal habe ich es verwendet, um einen einfachen Online-Chatroom zu erstellen~

1 Laden Sie die neueste Version von Workerman herunter

Sie können loslegen http://www.workerman.net Zum Download gehen

Ich habe Service und Client in zwei Ordner getrennt, um die Verwaltung zu erleichtern

Die allgemeine Projektstruktur ist wie folgt.

So implementieren Sie einen Online-Chat mit Workerman

Kunde:

Der Kunde ist einfach. Ein einfacher HTML-Code. Eingebettet in einen Websocket-Listening-Dienst

var ws, name, client_list={};
function connect() {
       // 创建websocket
       ws = new WebSocket("ws://192.168.0.88:2345");
       // 当socket连接打开时,输入用户名
       ws.onopen = onopen;
       // 当有消息时根据消息类型显示不同信息
       ws.onmessage = onmessage;
       ws.onclose = function() {
          console.log("连接关闭,定时重连");
          connect();
       };
       ws.onerror = function() {
          console.log("出现错误");
       };
    }

, um das Öffnen, die Nachrichtenüberwachung und das Schließen von Websockets zu realisieren

1 Wenn ein Client geöffnet wird, wird sofort ein Dialogfeld zur Eingabe eines Namens angezeigt

function onopen(){
        //console.log(name);
        //var username=connect_id="";
        if(!name)
        {
            name=prompt("请输入您的名字","");
            if(!name || name=='null'){ 
                name = '咕哒子';
            }
        }
 
        $('#curuser').text(name);
 
         data='{"type":"1","user":"'+name+'"}';
         
        ws.send(data);
    }

und pushe die Daten an den Server. Typ = 1 steht für Login.

2. Bestimmen Sie beim Empfang einer Nachricht den Nachrichtentyp, ob es sich um eine Gruppennachricht oder eine private Nachricht handelt. Und dann verarbeiten.

Darüber hinaus wird jedes Mal, wenn sich ein neuer Benutzer anmeldet, eine Benutzerliste an jeden Client gesendet. Rendern Sie

function onmessage(e){
        //console.log(e.data);
        var data = eval("("+e.data+")");
        var info=$('#chatinfo').html();
        if(data.type==1)
            $(&#39;#chatinfo&#39;).html(info+&#39;<br/>&#39;+data.data);
        else if(data.type==2)
        {
            // 在线用户列表 userinfo
            $(&#39;#userinfo&#39;).html(data.data);
        }
        else if(data.type==3)
        {
            // 在线用户列表 个人信息
            name=data.data.userinfo;
            //console.log(data.data);
        }
    }

und dann gibt es den Code für jeden Benutzer zum Senden von Nachrichten. Es kann ein privater Chat oder eine Gruppennachricht sein

$(&#39;#send&#39;).click(function(e){
        var msg=$(&#39;#msg&#39;).val();
        var tofriend=$(&#39;#tofriend&#39;).val();
        var tofriendname=$(&#39;#tofriendname&#39;).val();
        if(tofriend!="")
        {
            data=&#39;{"type":"3","user":"&#39;+name+&#39;","msg":"&#39;+msg+&#39;","friend_id":"&#39;+tofriend+&#39;","friendname":"&#39;+tofriendname+&#39;"}&#39;;
        }else{
            data=&#39;{"type":"2","user":"&#39;+name+&#39;","msg":"&#39;+msg+&#39;"}&#39;;
        }
        ws.send(data);
        $(&#39;#msg&#39;).attr("value",&#39;&#39;);
    });

Das ist so ziemlich alles auf dem Client.

Der Client hat mehrere Fallstricke,

Pit 1. Wenn der Variablenname name ist, wird er beim Aktualisieren der Webseite nicht zurückgesetzt, andernfalls wird er zurückgesetzt. (Nachdem ich die Informationen überprüft hatte, stellte ich fest, dass die Namensvariable window.name ist. Daher wird der Wert beim Aktualisieren der Webseite nicht aktualisiert.)

Pit 2. Für das JS-Gruppenarray sollte die Variable „ " und die äußerste Ebene ist '' Zum Beispiel: data='{"type":"1","user":"'+name+'"}'; Andernfalls kommt es zu Problemen beim Parsen. Andersherum geht es nicht!

Serverseite:

Die Serverseite ist hauptsächlich die Worker-Komponente und verwendet die verteilte Kommunikationskomponente des Kanals, um Abonnements, Cluster-Push, Gruppen-Push und privaten Chat zu implementieren.

Zunächst geht es natürlich um die Überwachung, um die Websocket-Überwachung eines Arbeiters zu aktivieren.

// 创建一个Worker监听2346端口,使用websocket协议通讯
$ws_worker = new Worker("websocket://0.0.0.0:2345");
$channel_server = new Channel\Server(&#39;0.0.0.0&#39;, 2206);
// 启动4个进程对外提供服务
$ws_worker->count = 4;
$ws_worker->name="kinmoschat";

Wenn die Arbeiter-Mann-Überwachung aktiviert ist, registrieren Sie die Kanalkommunikation.

$ws_worker->onWorkerStart=function($ws_worker)
{
    // channel 客户端链接上 服务器
    Channel\Client::connect(&#39;127.0.0.1&#39;,2206);
    $event_name=&#39;私聊&#39;;
    // 订阅 worker-<id 事件,并注册事件处理函数
    Channel\Client::on($event_name,function($event_data)use($ws_worker){
 
        //print_r($event_data);
        //print_r($ws_worker->connections);
        $to_connect_id=$event_data[&#39;to_connection_id&#39;];
        $message=$event_data[&#39;content&#39;];
 
        foreach ($ws_worker->connections as $connection) {
 
            if($connection->id==$to_connect_id)
            {
                $connection->send($message);
            }
                 
        }
 
        // if(!isset($ws_worker->connections[$to_connect_id]))
        // {
        //     echo &#39;connect is not exist\n&#39;;
        //     return;
        // }
        // $to_connection=$ws_worker->connections[$to_connect_id];
        // $to_connection->send($message);
    });
 
    // 订阅广播事件
    $event_name = &#39;广播&#39;;
    // 收到广播 向所有客户端发送消息
    Channel\Client::on($event_name,function($event_data)use($ws_worker){
        //print_r($event_data);
        $message=$event_data[&#39;content&#39;];
        foreach ($ws_worker->connections as $connection) {
            $connection->send($message);
        }
    });
};

Registrieren Sie zwei Ereignisse, ein Broadcast-Ereignis, ein privates Chat-Ereignis, eine Übertragung zur Online-Benachrichtigung und eine Gruppennachricht. Privater Chat ist privater Chat. . Hier können Sie auch Gruppenversand durchführen. Diese Version wurde jedoch noch nicht implementiert.

Dann gibt es einen Rückruf für den Client-Link.

$ws_worker->onConnect=function($connection){
    $connection->id = md5($connection->id."_".time()."_".rand(10000,99999));
};

Hier ruft der Client zurück und ich werde die Verbindungs-ID des Clients ändern. Ein einfacher MD5 dient hauptsächlich dazu, zu verhindern, dass serielle IDs zu leicht ausgenutzt werden. .

Dann der Hauptteil des gesamten Projekts, der Rückruf für die serverseitige Nachrichtenverarbeitung.

Weisen Sie für jeden eingehenden Kunden eine eindeutige ID zu.

Behalten Sie eine Beziehungstabelle mit connectid=>Benutzer bei.

Da mehrere Prozesse geöffnet werden, wird sie in der Sitzung gespeichert ungültig, daher ist eine Speicherung in der Datenbank geplant

Wenn die Verbindung getrennt wird, löschen Sie die Daten

$ws_worker->onMessage = function($connection, $data)
{
    $res=array(&#39;code&#39;=>200, &#39;msg&#39;=>&#39;ok&#39;, &#39;data&#39;=>null,&#39;type&#39;=>1);
    // 向客户端发送hello $data
    //print_r($data);
    $data=json_decode($data,true);
    //print_r($data);
    if(!isset($data[&#39;type&#39;])||empty($data[&#39;type&#39;]))// type 1  2
    {
        $res=array(&#39;code&#39;=>301, &#39;msg&#39;=>&#39;消息包格式错误&#39;, &#39;data&#39;=>null);
    }else{
        switch ($data[&#39;type&#39;]) {
            case &#39;1&#39;: // 客户端上线消息
                //print_r($connection->id);
                 
                if(!isset($data[&#39;user&#39;])||empty($data[&#39;user&#39;]))
                {
                    $res=array(&#39;code&#39;=>301, &#39;msg&#39;=>&#39;消息包格式错误&#39;, &#39;data&#39;=>null);
                    break;
                }
                // 维护一个数组 保存 用户 connection_id => user
 
                $dsn=&#39;mysql:host=127.0.0.1;dbname=kinmoschat;&#39;;
                $pdo=new PDO($dsn,&#39;root&#39;,&#39;123456&#39;);
                //准备SQL语句
                $sql = "INSERT INTO `user`(`connect_id`,`username`) VALUES (:connect_id,:username)";
 
                //调用prepare方法准备查询
                $stmt = $pdo->prepare($sql);
 
                //传递一个数组为预处理查询中的命名参数绑定值,并执行SQL
                $stmt->execute(array(&#39;:connect_id&#39; => $connection->id,&#39;:username&#39; => $data[&#39;user&#39;]));
                //获取最后一个插入数据的ID值
                //echo $pdo->lastInsertId() . &#39;<br />&#39;;
 
                // 向自己推送一条消息
                $res2[&#39;type&#39;]=3;// 系统信息
                $res2[&#39;data&#39;]=array(&#39;userinfo&#39; =>$data[&#39;user&#39;]);// 系统信息
                $connection->send(json_encode($res2));
 
                $msg="用户 ".$data[&#39;user&#39;]." 上线了~~";
                $res[&#39;data&#39;]=$msg;
                break;
            case &#39;2&#39;: // 客户端群发送消息
                if(!isset($data[&#39;user&#39;])||empty($data[&#39;user&#39;])||!isset($data[&#39;msg&#39;])||empty($data[&#39;msg&#39;]))
                {
                    $res=array(&#39;code&#39;=>301, &#39;msg&#39;=>&#39;消息包格式错误&#39;, &#39;data&#39;=>null);
                    break;
                }
                $msg="用户 ".$data[&#39;user&#39;]."说:".$data[&#39;msg&#39;];
                $res[&#39;data&#39;]=$msg;
                break;
            case &#39;3&#39;: // 客户端私聊
                if(!isset($data[&#39;user&#39;])||empty($data[&#39;user&#39;])||!isset($data[&#39;msg&#39;])||empty($data[&#39;msg&#39;])||!isset($data[&#39;friend_id&#39;])||empty($data[&#39;friend_id&#39;]))
                {
                    $res=array(&#39;code&#39;=>301, &#39;msg&#39;=>&#39;消息包格式错误&#39;, &#39;data&#39;=>null);
                    break;
                }
                $msg="用户 ".$data[&#39;user&#39;]."对您说:".$data[&#39;msg&#39;];
                $res[&#39;data&#39;]=$msg;
                $res[&#39;type&#39;]=1;// 聊天消息
                $res1=json_encode($res);
                // 推送给单个用户
                $event_name = &#39;私聊&#39;;
                Channel\Client::publish($event_name, array(
                    &#39;content&#39;          => $res1,
                    &#39;to_connection_id&#39; =>$data[&#39;friend_id&#39;]
                ));
                // 另外还要给自己推条消息
                $msg="您对 ".$data[&#39;friendname&#39;]."说:".$data[&#39;msg&#39;];
                $res[&#39;data&#39;]=$msg;
                $res[&#39;type&#39;]=1;// 聊天消息
                $res2=json_encode($res);
                Channel\Client::publish($event_name, array(
                    &#39;content&#39;          => $res2,
                    &#39;to_connection_id&#39; =>$connection->id
                ));
                return;
                break;
             
            default:
                # code...
                break;
        }
    }
    $res[&#39;type&#39;]=1;// 聊天消息
    $res=json_encode($res);
    // 广播给所有客户端
    $event_name = &#39;广播&#39;;
    Channel\Client::publish($event_name, array(
        &#39;content&#39;          => $res
    ));
 
    $dsn=&#39;mysql:host=127.0.0.1;dbname=kinmoschat;&#39;;
    $dbh=new PDO($dsn,&#39;root&#39;,&#39;123456&#39;);
    $stmt=$dbh->query(&#39;SELECT connect_id,username FROM user&#39;);
    $row=$stmt->fetchAll();
    $uerHtml="";
    foreach ($row as $key => $value) {
 
        $uerHtml.=&#39;<a class="user" onclick="userclick(\&#39;&#39;.$value[&#39;username&#39;].&#39;\&#39;,\&#39;&#39;.$value[&#39;connect_id&#39;].&#39;\&#39;);" value="&#39;.$value[&#39;connect_id&#39;].&#39;" href="javascript:void(0);">&#39;.$value[&#39;username&#39;].&#39;</a><br/>&#39;;
    }
    //print_r($row);
    $res1[&#39;type&#39;]=2;// 用户消息
    $res1[&#39;data&#39;]=$uerHtml;
    $res1=json_encode($res1);
     
 
    $event_name = &#39;广播&#39;;
    Channel\Client::publish($event_name, array(
        &#39;content&#39;          => $res1
    ));
};

Hier wird der connectid=>name jedes Benutzers in der Datenbank gespeichert. .

Wenn Sie eine Online-Nachricht erhalten, senden Sie diese an alle Benutzer.

Eine Gruppennachricht erhalten. . An alle Kunden senden.

Private Nachricht erhalten. Schicken Sie es dann einzeln an sich selbst und die Person, die es gesendet hat.

Hören Sie sich das Client-Schließereignis an und löschen Sie die relevanten Datensätze in der Benutzertabelle.

// 关闭链接 将数据库中的该数据删除
$ws_worker->onClose=function($connection)
{
    //echo 3233;
    $dsn=&#39;mysql:host=127.0.0.1;dbname=kinmoschat;&#39;;
    $pdo=new PDO($dsn,&#39;root&#39;,&#39;123456&#39;);
    $sql="delete from user where connect_id=&#39;".$connection->id."&#39;";
    //print_r($sql);
    $pdo->exec($sql);
};

Für weitere Workerman-Kenntnisse beachten Sie bitte das Workerman-Tutorial Spalte.

Das obige ist der detaillierte Inhalt vonSo implementieren Sie einen Online-Chat mit Workerman. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen