侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

php基于websocket搭建简易聊天室实践

php  /  管理员 发布于 7年前   193

本文实例讲述了php基于websocket搭建简易聊天室实践。分享给大家供大家参考。具体如下:
1、前言

公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室。于是搜集各种资料看文档、找实例自己也写了个简单的聊天室。

http连接分为短连接和长连接。短连接一般可以用ajax实现,长连接就是websocket。短连接实现起来比较简单,但是太过于消耗资源。websocket高效不过兼容存在点问题。websocket是html5的资源

2、前端

前端实现websocket很简单直接

//连接websocketvar 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  并返回 其中完成套接字的创建和握手操作

下图是一张详细的服务端处理websocket的流程图

3.2 代码实践

服务端做的流程大致是:

  1. 挂起一个socket套接字进程等待连接
  2. 有socket连接之后遍历套接字数组
  3. 没有握手的进行握手操作,如果已经握手则接收数据解析并写入缓冲区进行输出

下面是示例代码(我写的是一个类所以代码是根据函数分段的),文底给出github地址以及自己遇到的一些坑
 1、首先是创建套接字
 

//建立套接字    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);//如果接收的字节是0if($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地址[email protected]:rsaLive/websocket.git

①最好在控制台运行server.php

转到server.php脚本目录(可以先php -v 看下有没有配置php如果没有Linux配置下bash windows 配置下path)

php -f server.php

如果有错误会提示

②通过服务器访问html文件

8、踩过的坑,打开调试工作方便查看错误

①server.php 挂起的进程中可以打印输出的,如果出现问题可以在代码中加入打印来调试

可以在各个判断里面做标记在控制台查看代码运行在哪个区间

不过每次修改完代码之后需要重新运行脚本 php server.php

②如果出现这种错误可能是

1、在与服务器初始套接字的时候发送数据 (在第一次与服务器验证握手的时候不能发送内容)

2、如果已经验证过了但是客户端没有发送或者发送的消息为空也会出现这样的情况

所以要检验已连接的套接字的数据

 

③可能浏览器不支持或者服务端没有开启socket开始之前最好验证下

if (window.WebSocket){  console.log("This browser supports WebSocket!");} else {  console.log("This browser does not support WebSocket.");}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

您可能感兴趣的文章:

  • PHP实现简单聊天室(附源码)
  • 基于HTTP长连接的"服务器推"技术的php 简易聊天室
  • 简单的php+mysql聊天室实现方法(附源码)
  • 用PHP+MySQL搭建聊天室功能实例代码
  • php socket实现的聊天室代码分享
  • php+html5基于websocket实现聊天室的方法
  • 发布一个迷你php+AJAX聊天程序[聊天室]提供下载
  • 值得分享的php+ajax实时聊天室
  • 基于PHP+MySQL的聊天室设计
  • 基于Swoole实现PHP与websocket聊天室
  • PHP+mysql+ajax轻量级聊天室实现方法详解
  • PHP聊天室简单实现方法详解


  • 上一条:
    PHP实现简易blog的制作
    下一条:
    详解php中 === 的使用
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 用Time Warden监控PHP中的代码处理时间(0个评论)
    • 在PHP中使用array_pop + yield实现读取超大型目录功能示例(0个评论)
    • Property Hooks RFC在PHP 8.4中越来越接近现实(0个评论)
    • 近期文章
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(95个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-11
    • 2017-12
    • 2018-01
    • 2018-02
    • 2018-03
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-09
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    • 2024-05
    • 2024-06
    • 2024-07
    • 2024-09
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客