zoukankan      html  css  js  c++  java
  • WebSocket 长连接 及超时问题解决

    <?php
    set_time_limit(0);
    class SocketService { private $address = 'localhost'; private $port = 80; private $_sockets; public function __construct($address = '', $port='') { 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)." "); } 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('failed to accept socket: '.socket_strerror($_sock)." "); # 返回描述套接字错误的字符串 } $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, 'Please input a argument:'); $response = trim(fgets(STDIN)); // $this->send($_sock, $response); # 第二个参数是获取数据 要发送的信息 $this->send($_sock, '在线'); } } } } /** * 握手处理 * @param $newClient socket * @return int 接收到的信息 */ public function handshaking($newClient, $line){ $headers = array(); $lines = preg_split("/ /", $line); # 通过一个正则表达式分隔字符串。 foreach($lines as $line) { $line = chop($line); # 移除字符串右端的空白字符或其他预定义字符 if(preg_match('/A(S+): (.*)z/', $line, $matches)) { $headers[$matches[1]] = $matches[2]; } } $secKey = $headers['Sec-WebSocket-Key']; $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake " . "Upgrade: websocket " . "Connection: Upgrade " . "WebSocket-Origin: $this->address " . "WebSocket-Location: ws://$this->address:$this->port/服务器地址 ". "Sec-WebSocket-Accept:$secAccept "; 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();

    网上看到很多说会断开链接,设置心跳包也没有用

    我这里直接配置了下 set_time_limit(0);   改变 php.ini中的 max_execution_time设置时间 然后就没有断线的问题了! 也保证了持久连接!

    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;
                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 {
                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;
                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 = 'ws://localhost:80/websocket/test2.php'; var websocket; websocket = new WebSocket(wsurl); //连接建立 websocket.onopen = function(evevt){ console.log("Connected to WebSocket server."); $('.show-area').append('<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>Connected to WebSocket server!</p>'); } //收到消息 websocket.onmessage = function(event) { console.log(event); $('.show-area').append('<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>'+event.data+'</p>'); } //发生错误 websocket.onerror = function(event){ console.log("Connected to WebSocket server error"); $('.show-area').append('<p class="bg-danger message"><a name=""></a><i class="glyphicon glyphicon-info-sign"></i>Connect to WebSocket server error.</p>'); } //连接关闭 websocket.onclose = function(event){ console.log('websocket Connection Closed. '); $('.show-area').append('<p class="bg-warning message"><a name=""></a><i class="glyphicon glyphicon-info-sign"></i>websocket Connection Closed.</p>'); } // 发送信息 function send(){ var name = $('#name').val(); var message = $('#message').val(); if(!name){ alert('请输入用户名!'); return false; } if(!message){ alert('发送消息不能为空!'); return false; } var msg = { message: message, name: name }; try{ websocket.send(JSON.stringify(msg)); } catch(ex) { console.log(ex); } } //点发送按钮发送消息 $('.send').bind('click',function(){ send(); }); </script> </body> </html>
    作者地址:https://www.cnblogs.com/G921123/
    创作也有乐趣 知识分享 转载注明出处 相互理解 谢谢! WeChat:17321295203
  • 相关阅读:
    The Quad
    将OrCAD Capture CIS的设计文件(.dsn)导入到PADS Logic VX.2.3
    OrCAD Capture CIS 16.6 将版本16.6的设计文件另存为版本16.2的设计文件
    Eclipse IDE 添加jar包到Java工程中
    PADS Logic VX.2.3 修改软件界面语言
    切换Allegro PCB Editor
    Allegro PCB Design GXL (legacy) 将brd文件另存为低版本文件
    Allegro PCB Design GXL (legacy) 设置自动保存brd文件
    Could not create an acl object: Role '16'
    windows 下apache开启FastCGI
  • 原文地址:https://www.cnblogs.com/G921123/p/10254762.html
Copyright © 2011-2022 走看看