Connexions longues et problèmes de délai d'attente dans WebSocket (code)

不言
Libérer: 2023-04-04 18:20:02
avant
8617 Les gens l'ont consulté

Cet article vous apporte du contenu sur les connexions longues et les problèmes de délai d'attente dans WebSocket (code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.

<?php
set_time_limit(0);
class SocketService
{
    private $address  = &#39;localhost&#39;;
    private $port = 80;
    private $_sockets;
    public function __construct($address = &#39;&#39;, $port=&#39;&#39;)
    {
        if(!empty($address)){
            $this->address = $address;
        }
        if(!empty($port)) {
            $this->port = $port;
        }
    }

    public function service(){
        //获取tcp协议号码。
        $tcp = getprotobyname("SOL_TCP");           # 获取与协议名称关联的协议号
        $sock = socket_create(AF_INET, SOCK_STREAM, $tcp);  # 创建一个套接字(通讯节点)
        socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1);  # 设置套接字选项
        if($sock < 0)
        {
            throw new Exception("failed to create socket: ".socket_strerror($sock)."\n");
        }
        socket_bind($sock, $this->address, $this->port);    # 绑定
        socket_listen($sock, $this->port);      # 监听套接字上的连接
        $this->_sockets = $sock;   
    }

    public function run(){
        $this->service();
        $clients[] = $this->_sockets;   # 数组存储 每个socket
        # 让服务器无限获取客户端传过来的信息
        while (true){
            $changes = $clients;
            $write = NULL;
            $except = NULL;
            socket_select($changes,  $write,  $except, NULL);
            foreach ($changes as $key => $_sock){
                if($this->_sockets == $_sock){  # 判断是不是新接入的socket
                    if(($newClient = socket_accept($_sock))  === false){    # 接受新的套接字上的连接   socket_accept的作用就是接受socket_bind()所绑定的主机发过来的套接流
                        die(&#39;failed to accept socket: &#39;.socket_strerror($_sock)."\n");  # 返回描述套接字错误的字符串
                    }
                    $line = trim(socket_read($newClient, 1024));  # 读取客户端传过来的资源,并转化为字符串     socket_read的作用就是读出socket_accept()的资源并把它转化为字符串
                    $this->handshaking($newClient, $line);
                    //获取client ip
                    socket_getpeername ($newClient, $ip);                                   # 查询给定套接字的远程端,这可能导致主机/端口或UNIX文件系统路径,具体取决于其类型。
                    $clients[$ip] = $newClient;
                } else {
                    # 读取该socket的信息,注意:第二个参数是引用传参即接收数据,第三个参数是接收数据的长度
                    $lenght = socket_recv($_sock, $buffer,  2048, 0);               # 从已连接的socket接收数据   $lenght 接收到字符串长度
                    $msg = $this->message($buffer);          # 接收到的信息
                    //在这里业务代码
                    fwrite(STDOUT, &#39;Please input a argument:&#39;);
                    $response = trim(fgets(STDIN));
//                    $this->send($_sock, $response);                                                       # 第二个参数是获取数据    要发送的信息
                    $this->send($_sock, &#39;在线&#39;);
                }
            }
        }
    }

    /**
     * 握手处理
     * @param $newClient socket
     * @return int  接收到的信息
     */
    public function handshaking($newClient, $line){
        $headers = array();
        $lines = preg_split("/\r\n/", $line);   # 通过一个正则表达式分隔字符串。
        foreach($lines as $line)
        {
            $line = chop($line);    # 移除字符串右端的空白字符或其他预定义字符
            if(preg_match(&#39;/\A(\S+): (.*)\z/&#39;, $line, $matches))
            {
                $headers[$matches[1]] = $matches[2];
            }
        }
        $secKey = $headers[&#39;Sec-WebSocket-Key&#39;];
        $secAccept = base64_encode(pack(&#39;H*&#39;, sha1($secKey . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;)));
        $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
            "Upgrade: websocket\r\n" .
            "Connection: Upgrade\r\n" .
            "WebSocket-Origin: $this->address\r\n" .
            "WebSocket-Location: ws://$this->address:$this->port/服务器地址\r\n".
            "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
        return socket_write($newClient, $upgrade, strlen($upgrade));    # socket_write的作用是向socket_create的套接流写入信息,或者向socket_accept的套接流写入信息
    }

    /**
     * 解析接收数据
     * @param $buffer
     * @return null|string
     */
    public function message($buffer){
        $len = $masks = $data = $decoded = null;
        $len = ord($buffer[1]) & 127;
        if ($len === 126)  {
            $masks = substr($buffer, 4, 4);
            $data = substr($buffer, 8);
        } else if ($len === 127)  {
            $masks = substr($buffer, 10, 4);
            $data = substr($buffer, 14);
        } else  {
            $masks = substr($buffer, 2, 4);
            $data = substr($buffer, 6);
        }
        for ($index = 0; $index < strlen($data); $index++) {
            $decoded .= $data[$index] ^ $masks[$index % 4];
        }
        return $decoded;
    }

    /**
     * 发送数据
     * @param $newClinet 新接入的socket
     * @param $msg   要发送的数据
     * @return int|string
     */
    public function send($newClinet, $msg){
        $msg = $this->frame($msg);
        socket_write($newClinet, $msg, strlen($msg));   # 写入套接字
    }

    public function frame($s) {
        $a = str_split($s, 125);    # 把字符串分割到数组中 第二个长度参数
        if (count($a) == 1) {
            return "\x81" . chr(strlen($a[0])) . $a[0];
        }
        $ns = "";
        foreach ($a as $o) {
            $ns .= "\x81" . chr(strlen($o)) . $o;
        }
        return $ns;
    }

    /**
     * 关闭socket
     */
    public function close(){
        # socket_close的作用是关闭socket_create()或者socket_accept()所建立的套接流
        return socket_close($this->_sockets);
    }
}

$sock = new SocketService();
$sock->run();
Copier après la connexion


J'ai vu beaucoup de choses sur Internet disant que le lien sera déconnecté et que le réglage du package Heartbeat est inutile

Je le configure directement ici Set_time_limit(0); Modifiez l'heure de réglage max_execution_time dans php.ini et il n'y aura pas de problème de déconnexion. Les connexions persistantes sont également garanties !

Partie HTML


<!DOCTYPE html>
<html>
<head>
    <title>Socket 测试</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
    <link href="https://cdn.bootcss.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">

 <style type="text/css">
        html, body {
            min-height: 100%; }

        body {
            margin: 0;
            padding: 0;
            width: 100%;
            font-family: "Microsoft Yahei",sans-serif, Arial; }

        .container {
            text-align: center; }

        .title {
            font-size: 16px;
            color: rgba(0, 0, 0, 0.3);
            position: fixed;
            line-height: 30px;
            height: 30px;
            left: 0px;
            right: 0px;
            background-color: white; }

        .content {
            background-color: #f1f1f1;
            border-top-left-radius: 6px;
            border-top-right-radius: 6px;
            margin-top: 30px; }
        .content .show-area {
            text-align: left;
            padding-top: 8px;
            padding-bottom: 168px; }
        .content .show-area .message {
            width: 70%;
            padding: 5px;
            word-wrap: break-word;
            word-break: normal; }
        .content .write-area {
            position: fixed;
            bottom: 0px;
            right: 0px;
            left: 0px;
            background-color: #f1f1f1;
            z-index: 10;
            width: 100%;
            height: 160px;
            border-top: 1px solid #d8d8d8; }
        .content .write-area .send {
            position: relative;
            top: -28px;
            height: 28px;
            border-top-left-radius: 55px;
            border-top-right-radius: 55px; }
        .content .write-area #name{
            position: relative;
            top: -20px;
            line-height: 28px;
            font-size: 13px; }
    </style>

</head>
<body>
<div class="container">
    <div class="title">Socket 测试长连接</div>
    <div class="content">
        <div class="show-area"></div>
        <div class="write-area">
            <div><button class="btn btn-default send" >发送</button></div>
            <div><input name="name" id="name" type="text" placeholder="input your name"></div>
            <div>
                <textarea name="message" id="message" cols="38" rows="4" placeholder="input your message..."></textarea>
            </div>
        </div>
    </div>
</div>

<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script>
        var wsurl = &#39;ws://localhost:80/websocket/test2.php&#39;;
        var websocket;
        websocket = new WebSocket(wsurl);
            //连接建立
            websocket.onopen = function(evevt){
                console.log("Connected to WebSocket server.");
                $(&#39;.show-area&#39;).append(&#39;<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>Connected to WebSocket server!</p>&#39;);
            }
            //收到消息
            websocket.onmessage = function(event) {
                console.log(event);
                $(&#39;.show-area&#39;).append(&#39;<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>&#39;+event.data+&#39;</p>&#39;);
            }

            //发生错误
            websocket.onerror = function(event){
                console.log("Connected to WebSocket server error");
                $(&#39;.show-area&#39;).append(&#39;<p class="bg-danger message"><a name=""></a><i class="glyphicon glyphicon-info-sign"></i>Connect to WebSocket server error.</p>&#39;);
            }

            //连接关闭
            websocket.onclose = function(event){
                console.log(&#39;websocket Connection Closed. &#39;);
                $(&#39;.show-area&#39;).append(&#39;<p class="bg-warning message"><a name=""></a><i class="glyphicon glyphicon-info-sign"></i>websocket Connection Closed.</p>&#39;);
            }

    // 发送信息
            function send(){
                var name = $(&#39;#name&#39;).val();
                var message = $(&#39;#message&#39;).val();
                if(!name){
                    alert(&#39;请输入用户名!&#39;);
                    return false;
                }
                if(!message){
                    alert(&#39;发送消息不能为空!&#39;);
                    return false;
                }
                 var msg = {
                     message: message,
                     name: name
                 };
                try{
                     websocket.send(JSON.stringify(msg));
                } catch(ex) {
                    console.log(ex);
                }
            }
            //点发送按钮发送消息
            $(&#39;.send&#39;).bind(&#39;click&#39;,function(){
                send();
            });

</script>
</body>
</html>
Copier après la connexion


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal