本篇文章主要讲解 php+websocket 搭建简易聊天室实践, 文中有关 php,websocket 的内容, 请有需要的人参考
本文实例讲述了 php 基于 websocket 搭建简易聊天室实践分享给大家供大家参考具体如下:
1 前言
公司游戏里面有个简单的聊天室, 了解了之后才知道是 node+websocket 做的, 想想 php 也来做个简单的聊天室于是搜集各种资料看文档找实例自己也写了个简单的聊天室
http 连接分为短连接和长连接短连接一般可以用 ajax 实现, 长连接就是 websocket 短连接实现起来比较简单, 但是太过于消耗资源 websocket 高效不过兼容存在点问题 websocket 是 html5 的资源
2 前端
前端实现 websocket 很简单直接
- // 连接 websocket
- var ws = new WebSocket("ws://127.0.0.1:8000");
- // 成功连接 websoc 的时候
- ws.onopen = function(){}
- // 成功获取服务端输出的消息
- ws.onmessage = function(e){}
- // 连接错误的时候
- ws.onerror = function(){}
- // 向服务端发送数据
- ws.send();
3 后台
websocket 的难点主要在后台
3.1websocket 连接过程
websocket 通信图解 这是一个简易的客户端和服务端的通信图解, php 主要就做的就是接受加密 key 并返回 其中完成套接字的创建和握手操作
- // 建立套接字
- public function createSocket($address,$port)
- {
- // 创建一个套接字
- $socket= socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
- // 设置套接字选项
- socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
- // 绑定 IP 地址和端口
- socket_bind($socket,$address,$port);
- // 监听套接字
- socket_listen($socket);
- return $socket;
- }
2 将套接字放入数组
- public function __construct($address,$port)
- {
- // 建立套接字
- $this->soc=$this->createSocket($address,$port);
- $this->socs=array($this->soc);
- }
3 挂起进程遍历套接字数组, 主要操作都是在这里面完成的
- public function run(){
- // 挂起进程
- while(true){
- $arr=$this->socs;
- $write=$except=NULL;
- // 接收套接字数字 监听他们的状态
- socket_select($arr,$write,$except, NULL);
- // 遍历套接字数组
- foreach($arr as $k=>$v){
- // 如果是新建立的套接字返回一个有效的 套接字资源
- if($this->soc == $v){
- $client=socket_accept($this->soc);
- if($client <0){
- echo "socket_accept() failed";
- }else{
- // array_push($this->socs,$client);
- // unset($this[]);
- // 将有效的套接字资源放到套接字数组
- $this->socs[]=$client;
- }
- }else{
- // 从已连接的 socket 接收数据 返回的是从 socket 中接收的字节数
- $byte=socket_recv($v, $buff,20480, 0);
- // 如果接收的字节是 0
- if($byte<7)
- continue;
- // 判断有没有握手没有握手则进行握手, 如果握手了 则进行处理
- if(!$this->hand[(int)$client]){
- // 进行握手操作
- $this->hands($client,$buff,$v);
- }else{
- // 处理数据操作
- $mess=$this->decodeData($buff);
- // 发送数据
- $this->send($mess,$v);
- }
- }
- }
- }
- }
4 进行握手 流程是接收 websocket 内容从 Sec-WebSocket-Key: 中获取 key 并通过加密算法写入缓冲区客户端会进行验证 (自动验证不需要我们处理)
- public function hands($client,$buff,$v)
- {
- // 提取 websocket 传的 key 并进行加密 (这是固定的握手机制获取 Sec-WebSocket-Key: 里面的 key)
- $buf = substr($buff,strpos($buff,'Sec-WebSocket-Key:')+18);
- // 去除换行空格字符
- $key = trim(substr($buf,0,strpos($buf,"\r\n")));
- // 固定的加密算法
- $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
- $new_message = "HTTP/1.1 101 Switching Protocols\r\n";
- $new_message .= "Upgrade: websocket\r\n";
- $new_message .= "Sec-WebSocket-Version: 13\r\n";
- $new_message .= "Connection: Upgrade\r\n";
- $new_message .= "Sec-WebSocket-Accept:" . $new_key . "\r\n\r\n";
- // 将套接字写入缓冲区
- socket_write($v,$new_message,strlen($new_message));
- // socket_write(socket,$upgrade.chr(0), strlen($upgrade.chr(0)));
- // 标记此套接字握手成功
- $this->hand[(int)$client]=true;
- }
5 解析客户端的数据 (我这里没有进行加密, 如果有需要也可以自己加密 )
- // 解析数据
- public
- function decodeData($buff) {
- //$buff 解析数据帧
- $mask = array();
- $data = '';
- $msg = unpack('H*', $buff); // 用 unpack 函数从二进制将数据解码
- $head = substr($msg[1], 0, 2);
- if (hexdec($head {
- 1
- }) === 8) {
- $data = false;
- } else if (hexdec($head {
- 1
- }) === 1) {
- $mask[] = hexdec(substr($msg[1], 4, 2));
- $mask[] = hexdec(substr($msg[1], 6, 2));
- $mask[] = hexdec(substr($msg[1], 8, 2));
- $mask[] = hexdec(substr($msg[1], 10, 2));
- // 遇到的问题 刚连接的时候就发送数据 显示 state connecting
- $s = 12;
- $e = strlen($msg[1]) - 2;
- $n = 0;
- for ($i = $s; $i <= $e; $i += 2) {
- $data. = chr($mask[$n % 4] ^ hexdec(substr($msg[1], $i, 2)));
- $n++;
- }
- // 发送数据到客户端
- // 如果长度大于 125 将数据分块
- $block = str_split($data, 125);
- $mess = array('mess' =>$block[0], );
- return $mess;
- }
6 将套接字写入缓冲区
- // 发送数据
- public function send($mess,$v)
- {
- // 遍历套接字数组 成功握手的 进行数据群发
- foreach ($this->socs as $keys => $values) {
- // 用系统分配的套接字资源 id 作为用户昵称
- $mess['name']="Tourist's socket:{$v}";
- $str=json_encode($mess);
- $writes ="\x81".chr(strlen($str)).$str;
- // ob_flush();
- // flush();
- // sleep(3);
- if($this->hand[(int)$values])
- socket_write($values,$writes,strlen($writes));
- }
- }
7 运行方法
github 地址 git@github.com:rsaLive/websocket.git
最好在控制台运行 server.php
转到 server.php 脚本目录 (可以先 php -v 看下有没有配置 php 如果没有 Linux 配置下 bash windows 配置下 path)
php -f server.php
可能浏览器不支持或者服务端没有开启 socket 开始之前最好验证下
- if (window.WebSocket){
- console.log("This browser supports WebSocket!");
- } else {
- console.log("This browser does not support WebSocket.");
- }
来源: https://www.php1.cn/detail/php-4d73489593.html