php之websocket通信

2 篇文章 0 订阅

html页面

<!DOCTYPE html>
<html>
<head>
    <title>chatdemo</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
</head>
<body>
<button onclick="send()">发送消息</button>
<script>
    socket = new WebSocket('ws://127.0.0.1:1935/');
    console.log(socket);
    // 打开Socket
    socket.onopen = function(event) {
        // 发送一个初始化消息
        socket.send("init msg");

    };
    socket.onmessage = function(event) {
        console.log('收到消息',event);
        console.log('收到消息',event.data);

    };
    // 监听Socket的关闭
    socket.onclose = function(event) {
        console.log('关闭监听',event);
    };
    function  send(){
        console.log('send');
        socket.send("client msg");
    }
</script>
</body>
</html>

websocket服务端

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2021/4/24 0024
 * Time: 11:57
 */

set_time_limit(0);

$ip = "127.0.0.1";
$port = 1935;

/*
 +-------------------------------
 *    @socket通信整个过程
 +-------------------------------
 *    @socket_create    //产生一个socket,相当于产生一个socket的数据结构
 *    @socket_bind      //把socket绑定在一个IP地址和端口上
 *    @socket_listen    //监听由指定socket的所有连接
 *    @socket_accept    //接受一个Socket连接
 *    @socket_read      //读取指定长度的数据
 *    @socket_write     //写数据到socket缓存
 *    @socket_close     //关闭一个socket资源
 +--------------------------------
 */
/**
 *  readyState
 *  0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
 *
 */
/*----------------    以下操作都是手册上的    -------------------*/
if(($sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0 ){
    echo "socket_create() 失败的原因是:".socket_strerror($sock)."\n";
}
if(($ret = socket_bind($sock,$ip,$port)) < 0) {
    echo "socket_bind() 失败的原因是:".socket_strerror($ret)."\n";
}
if(($ret = socket_listen($sock,4)) < 0) {
    echo "socket_listen() 失败的原因是:".socket_strerror($ret)."\n";
}

//连接的client socket 列表
$clients = array($sock);
while (true){
    $changed = $clients;    // 单独拷贝一份
    //以指定的超时时间对给定的套接字数组运行select()系统调用
    // 因为客户端是长连接,如果客户端非正常断开,服务端会在 socket_accept 阻塞,现在使用 select 非阻塞模式 socket
    socket_select($changed, $null, $null, 0, 10);
     //如果有新的连接 接收第一次 socket 连入,连入后移除服务端 socket
    if (in_array($sock, $changed)) {
        //接受并加入新的socket连接
        $client = socket_accept($sock);
        $buf = socket_read($client, 1024);
//        echo $buf;

        // 匹配 Sec-Websocket-Key 标识 //握手的逻辑start
        if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/i",$buf,$match)) {
            // 需要将 Sec-WebSocket-Key 值累加字符串,并依次进行 SHA-1 加密和 base64 加密
            $key = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
            // 拼凑响应内容
            $res= "HTTP/1.1 101 Switching Protocol".PHP_EOL
                ."Upgrade: WebSocket".PHP_EOL
                ."Connection: Upgrade".PHP_EOL
                ."WebSocket-Location: ws://127.0.0.1:1935".PHP_EOL
                ."Sec-WebSocket-Accept: " . $key .PHP_EOL.PHP_EOL;  // 注意这里,需要两个换行
            // 向客户端应答 Sec-WebSocket-Accept
            socket_write($client, $res, strlen($res));
            //握手的逻辑end


            // 向客户端发送消息
            socket_write($client, buildMsg('socket ok'), 1024);
            // 加入客户端 socket
            $clients[] = $client;
            // 移除服务端 socket
            $key = array_search($sock, $changed);
            unset($changed[$key]);
        }
    }
    // 循环所有客户端 sockets
    foreach ($changed as $s) {
        // 获取客户端发给服务端的内容
        $buf = socket_read($s, 8024);
//        echo strlen($buf).'---'.PHP_EOL;
        // 代表客户端主动关闭
        if(strlen($buf) < 9) {
            $key = array_search($s, $clients);
            unset($clients[$key]);
            socket_close($s);
            continue;
        }
        // 输出
        echo getMsg($buf).PHP_EOL;
    }
}
socket_close($sock);

// 编码服务端向客户端发送的内容
function buildMsg($msg) {
    $frame = [];
    $frame[0] = '81';
    $len = strlen($msg);
    if ($len < 126) {
        $frame[1] = $len < 16 ? '0' . dechex($len) : dechex($len);
    } else if ($len < 65025) {
        $s = dechex($len);
        $frame[1] = '7e' . str_repeat('0', 4 - strlen($s)) . $s;
    } else {
        $s = dechex($len);
        $frame[1] = '7f' . str_repeat('0', 16 - strlen($s)) . $s;
    }
    $data = '';
    $l = strlen($msg);
    for ($i = 0; $i < $l; $i++) {
        $data .= dechex(ord($msg{$i}));
    }
    $frame[2] = $data;
    $data = implode('', $frame);
    return pack("H*", $data);
}
// 解析客户端向服务端发送的内容
function getMsg($buffer) {
    $res = '';
    $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++) {
        $res .= $data[$index] ^ $masks[$index % 4];
    }
    return $res;
}

开启服务
在这里插入图片描述
接口
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值