当前位置: 移动技术网 > IT编程>开发语言>PHP > WebSocket 长连接 及超时问题解决

WebSocket 长连接 及超时问题解决

2019年01月12日  | 移动技术网IT编程  | 我要评论

宝鸡第一人才网,吉林省地方税务局网上申报,邮编100020

<?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)."\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('failed to accept socket: '.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, '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("/\r\n/", $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\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();

 

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

我这里直接配置了下 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;
            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 = '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>

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网