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;
}
开启服务
接口
转载:https://blog.csdn.net/hgb24660/article/details/116096902
查看评论