PHP第一篇:PHP WebSocket实现前后端数据交互,亲测可用(windows+ apache2.4 +php5.6 ) - Go语言中文社区

PHP第一篇:PHP WebSocket实现前后端数据交互,亲测可用(windows+ apache2.4 +php5.6 )


首先贴上参考的教程

①:https://blog.csdn.net/lian772882/article/details/81386115(主)

②:https://www.cnblogs.com/saonian/p/5504456.html(理解原理)

③:https://www.cnblogs.com/isdom/p/webclips028.html(参考解码方法)

根据①实现了简单的前后端交互,但是,参考②和③5,我针对我的情况成功的增加了两点:

1.允许服务器返回JSON格式的数据

2.获取客户端发送的数据(这一条有许多教程都实现了,比如拿聊天室,或者这篇教程的大佬

④:https://blog.csdn.net/qq_38568388/article/details/78340750),但是由于我参考这个,原理都一样,但很多东西不好改(主要还是懒。。。)

 

贴一张websocket的工作原理(from②): 

                                                        

再开始之前,先确认,你的php否开启了sockets扩展:

                                                              

websocket.php:

<?php
	
$address = "127.0.0.1";
$port = 9999; //调试的时候,可以多换端口来测试程序!
 
set_time_limit(0); 
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_block($sock);
socket_bind($sock, $address, $port);
socket_listen($sock, 4);
 
 
do
{
    echo "Waiting for Connection...n";
    $msgsock = socket_accept($sock);
    echo "Waiting for Request...n";
    $buf = socket_read($msgsock, 8192);     //读取请求
    echo "Request Received: $bufn";
    $response = hand_shake($buf);
    socket_write($msgsock,$response,strlen($response)); //发送响应
 
    //正式开始通信...
    $buf = socket_read($msgsock, 8192); //获取前端发送的消息

    //这里我用了③中的编码和解码方法mask和umaske,原来的无法正确的接收到客户端发的信息,乱码,
    //而且无法将json数据编码发送给前端,我是没成功。
    if (unmask($buf) == 'getPeerInfo') {
                //我要返回的json数据
     		   	$msg = '[{
		            "Addr": "/ip4/95.179.192.99/tcp/10001",
		            "Peer": "QmQFy5XWmtZ7U2nZu198qYW8LefvrBK3Y9b3V1MqUfuoRT",
		            "Latency": "",
		            "Muxer": "你好",
		            "Direction": 0,
		            "Streams": null
		        },
		        {
		            "Addr": "/ip4/95.216.192.206/tcp/4001",
		            "Peer": "QmZyVchYnNcRdCcikT29GNFGZscBdWeJ6BaWdTxZmm2V5M",
		            "Latency": "",
		            "Muxer": "你好",
		            "Direction": 0,
		            "Streams": null
		        },
		        {
		            "Addr": "/ip4/98.11.199.27/tcp/39853",
		            "Peer": "QmVvP46C4wqyKt4aGBsf9gsr482rnf65ZxP1Hh8v4xPgdD",
		            "Latency": "",
		            "Muxer": "",
		            "Direction": 0,
		            "Streams": null
		        },
		        {
		            "Addr": "/ipfs/QmRv1GNseNP/p2p-circuit",
		            "Peer": "QmVCgCcoeB9fqoat8jJS8XDxqEnVizNzTbz8JsM2NCUZcY",
		            "Latency": "",
		            "Muxer": "",
		            "Direction": 0,
		            "Streams": null
		        },
		        {
		            "Addr": "/ipfs/QmRv1GNseNP/p2p-circuit",
		            "Peer": "QmSEzrFkZQCN138uTHeJaBBH2GQ3Kq3XnUAx2iAMneTQsZ",
		            "Latency": "",
		            "Muxer": "",
		            "Direction": 0,
		            "Streams": null
		        }]';
    		$response_text = mask(json_encode($msg));  
    		socket_write($msgsock, $response_text, strlen($response_text));
     }else{
            //这里不建议用array,因为json_encode之后出现空值,可能是编码问题。
            //一旦编码出问题,就是返回空,又不报错
     		$msg = '{"error:"Invalid method"}';   
     		$response_text = mask(json_encode($msg));
    		socket_write($msgsock, $response_text, strlen($response_text));
     };
     socket_close($msgsock);
} while (true);
socket_close($sock);
 
function hand_shake($buf){
    $buf  = substr($buf,strpos($buf,'Sec-WebSocket-Key:')+18);
    $key  = trim(substr($buf,0,strpos($buf,"rn")));
 
    $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
 
    $new_message = "HTTP/1.1 101 Switching Protocolsrn";
    $new_message .= "Upgrade: websocketrn";
    $new_message .= "Sec-WebSocket-Version: 13rn";
    $new_message .= "Connection: Upgradern";
    $new_message .= "Sec-WebSocket-Accept: " . $new_key . "rnrn";
    return $new_message;
}


//解码数据
function unmask($text) {
    $length = ord($text[1]) & 127;
    if($length == 126) {
        $masks = substr($text, 4, 4);
        $data = substr($text, 8);
    }
    elseif($length == 127) {
        $masks = substr($text, 10, 4);
        $data = substr($text, 14);
    }
    else {
        $masks = substr($text, 2, 4);
        $data = substr($text, 6);
    }
    $text = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }
    return $text;
}

//function code($msg){
//     $msg = preg_replace(array('/r$/','/n$/','/rn$/',), '', $msg);
//     $frame = array();
//     $frame[0] = '81';
//     $len = strlen($msg);
//     $frame[1] = $len<16?'0'.dechex($len):dechex($len);
//     $frame[2] = ord_hex($msg);
//     $data = implode('',$frame);
//     return pack("H*", $data);
// }

function mask($text)
{
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);
    
    if($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
    elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
    return $header.$text;
}

//function ord_hex($data)  {
//    $msg = '';
//    $l = strlen($data);
//    for ($i= 0; $i<$l; $i++) {
//        $msg .= dechex(ord($data{$i}));
//    }
//    return $msg;
//}

?>

websocket.html:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <h3>WebSocket协议的客户端程序</h3>
  <button id="btConnect">连接到WS服务器</button>
  <button id="btSendAndReceive">向WS服务器发消息并接收消息</button>
  <button id="btClose">断开与WS服务器的连接</button>
  <div id="val"></div>
  <script>
    var wsClient = null; //WS客户端对象
 
    btConnect.onclick = function(){
      //连接到WS服务器,注意:协议名不是http!
      wsClient = new WebSocket('ws://127.0.0.1:9999');
      wsClient.onopen = function(){
        console.log('WS客户端已经成功连接到服务器上')
      }
    }
 
    btSendAndReceive.onclick = function(){
      //向WS服务器发送一个消息
      wsClient.send('getPeerInfo'); //发送的消息
      console.log('WS客户端向WS服务器发送一个消息')
      //接收WS服务器返回的消息
      wsClient.onmessage = function(e){
        console.log('WS客户端接收到一个服务器的消息:'+  JSON.parse(e.data)); //注意加json解析
        val.innerHTML=JSON.parse(e.data);
      }
 
      
    }
 
    btClose.onclick = function(){
      //断开到WS服务器的连接
      wsClient.close();  //向服务器发消息,主动断开连接
      wsClient.onclose = function(){
        //经过客户端和服务器的四次挥手后,二者的连接断开了
        console.log('到服务器的连接已经断开')
      }
    }
  </script>
</body>
</html>

运行测试:

1. 在你Apache访问目录,我的在(apache的htdocs ),打开cmd(shift+右键,能看到在此目录打开powershell/命令行终端)

运行:php websocket.php

                               

这样就可以开启了socket线程,等待客户端连接了。

2.浏览器访问:http://localhost/websocket_2.html,并F12打开浏览器控制台

3.先点击,连接服务器,在发送消息并接收,此后这次回话就结束了,所以你点断开没用。

至此已成功实现根据前端发送的数据,判断返回相应的json数据。但还有几点讨论跟大家说一下:

后续讨论:

1.你想一开始就初始化一个与服务器端的连接,可以参考④中的写法:

将:

wsClient = new WebSocket('ws://127.0.0.1:9999');
wsClient.onopen = function(){
    console.log('WS客户端已经成功连接到服务器上')
}

写在最外层:

                           

但是有个缺陷:你运行完发送消息之后,如果没有那个点击连接的按钮,那你只能重新刷新页面,因为运行之后就断开连接了。

其实能实现持续发送的,可以参考④,目前我没去改。

 

2.如果你的json从其他页面传过来,你需要注意编码,在代码中我也有提及,特别对中文,可以先用urlencode,在用urldecode例如我的:

                                                    

3.未完待续,我会研究下怎么加载页面后,可以直接连续点发送消息,再断开连接操作。。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/zhangtao0417/article/details/85263162
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-09-13 14:04:22
  • 阅读 ( 1467 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢