加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > PHP > 正文

php中使用websocket详解

发布时间:2020-05-23 09:14:51 所属栏目:PHP 来源:互联网
导读:网上也有一些关于php的websocket的实现,但是只有自己亲手写过之后才知道其中的感受。下面就把个人的一些心得给大家分享下

在PHP中,开发者需要考虑的东西比较多,从socket的连接、建立、绑定、监听等都需要开发者自己去操作完成,对于初学者来说,难度方面也挺大的,所以本文的思路如下:

1、socket协议的简介

2、介绍client与server之间的连接原理

3、PHP中建立socket的过程讲解

4、用一个聊天室作为实例详细讲解在PHP中如何使用socket

一、socket协议的简介

  WebSocket是什么,有什么优点

  WebSocket是一个持久化的协议,这是相对于http非持久化来说的。

  举个简单的例子,http1.0的生命周期是以request作为界定的,也就是一个request,一个response,对于http来说,本次client与server的会话到此结束;而在http1.1中,稍微有所改进,即添加了keep-alive,也就是在一个http连接中可以进行多个request请求和多个response接受操作。然而在实时通信中,并没有多大的作用,http只能由client发起请求,server才能返回信息,即server不能主动向client推送信息,无法满足实时通信的要求。而WebSocket可以进行持久化连接,即client只需进行一次握手,成功后即可持续进行数据通信,值得关注的是WebSocket实现client与server之间全双工通信,即server端有数据更新时可以主动推送给client端。

二、介绍client与server之间的socket连接原理

1、下面是一个演示client和server之间建立WebSocket连接时握手部分

2、client与server建立socket时握手的会话内容,即request与response

  a、client建立WebSocket时向服务器端请求的信息

  b、服务器获取到client请求的信息后,根据WebSocket协议对数据进行处理并返回,其中要对Sec-WebSocket-Key进行加密等操作

3、socket建立连接原理图:

三、PHP中建立socket的过程讲解

1、在PHP中,client与server之间建立socket通信,首先在PHP中创建socket并监听端口信息,代码如下:

2、设计一个循环挂起WebSocket通道,进行数据的接收、处理和发送

sockets; $write=NULL; $except=NULL;
/*
//这个函数是同时接受多个连接的关键,我的理解它是为了阻塞程序继续往下执行。
socket_select ($sockets,$write = NULL,$except = NULL,NULL);

$sockets可以理解为一个数组,这个数组中存放的是文件描述符。当它有变化(就是有新消息到或者有客户端连接/断开)时,socket_select函数才会返回,继续往下执行。
$write是监听是否有客户端写数据,传入NULL是不关心是否有写变化。
$except是$sockets里面要被排除的元素,传入NULL是”监听”全部。
最后一个参数是超时时间
如果为0:则立即结束
如果为n>1: 则最多在n秒后结束,如遇某一个连接有新动态,则提前返回
如果为null:如遇某一个连接有新动态,则返回
*/
socket_select($changes,$write,$except,NULL);
foreach($changes as $sock){

  //如果有新的client连接进来,则
  if($sock==$this->master){

    //接受一个socket连接
    $client=socket_accept($this->master);

    //给新连接进来的socket一个唯一的ID
    $key=uniqid();
    $this->sockets[]=$client; //将新连接进来的socket存进连接池
    $this->users[$key]=array(
      'socket'=>$client,//记录新连接进来client的socket信息
      'shou'=>false    //标志该socket资源没有完成握手
    );
  //否则1.为client断开socket连接,2.client发送信息
  }else{
    $len=0;
    $buffer='';
    //读取该socket的信息,注意:第二个参数是引用传参即接收数据,第三个参数是接收数据的长度
    do{
      $l=socket_recv($sock,$buf,1000,0);
      $len+=$l;
      $buffer.=$buf;
    }while($l==1000);

    //根据socket在user池里面查找相应的$k,即健ID
    $k=$this->search($sock);

    //如果接收的信息长度小于7,则该client的socket为断开连接
    if($len<7){
      //给该client的socket进行断开操作,并在$this->sockets和$this->users里面进行删除
      $this->send2($k);
      continue;
    }
    //判断该socket是否已经握手
    if(!$this->users[$k]['shou']){
      //如果没有握手,则进行握手处理
      $this->woshou($k,$buffer);
    }else{
      //走到这里就是该client发送信息了,对接受到的信息进行uncode处理
      $buffer = $this->uncode($buffer,$k);
      if($buffer==false){
        continue;
      }
      //如果不为空,则进行消息推送操作
      $this->send($k,$buffer);
    }
  }
}

}

}

3、以上服务器端完成的WebSocket的前期工作后,就等着client连接进行,client创建WebSocket很简单,代码如下:

//断开WebSocket连接
ws.onclose = function(){
ws = false;
}

四、聊天室实例代码

1、PHP部分

//地址与接口,即创建socket时需要服务器的IP和端口
$sk=new Sock('127.0.0.1',8000);

//对创建的socket循环进行监听,处理数据
$sk->run();

//下面是sock类
class Sock{
public $sockets; //socket的连接池,即client连接进来的socket标志
public $users; //所有client连接进来的信息,包括socket、client名字等
public $master; //socket的resource,即前期初始化socket时返回的socket资源

private $sda=array(); //已接收的数据
private $slen=array(); //数据总长度
private $sjen=array(); //接收数据的长度
private $ar=array(); //加密key
private $n=array();

public function __construct($address,$port){

//创建socket并把保存socket资源在$this->master
$this->master=$this->WebSocket($address,$port);

//创建socket连接池
$this->sockets=array($this->master);

}

//对创建的socket循环进行监听,处理数据
function run(){
//死循环,直到socket断开
while(true){
$changes=$this->sockets;
$write=NULL;
$except=NULL;

  /*
  //这个函数是同时接受多个连接的关键,我的理解它是为了阻塞程序继续往下执行。
  socket_select ($sockets,NULL);

  $sockets可以理解为一个数组,这个数组中存放的是文件描述符。当它有变化(就是有新消息到或者有客户端连接/断开)时,socket_select函数才会返回,继续往下执行。
  $write是监听是否有客户端写数据,传入NULL是不关心是否有写变化。
  $except是$sockets里面要被排除的元素,传入NULL是”监听”全部。
  最后一个参数是超时时间
  如果为0:则立即结束
  如果为n>1: 则最多在n秒后结束,如遇某一个连接有新动态,则提前返回
  如果为null:如遇某一个连接有新动态,则返回
  */
  socket_select($changes,NULL);
  foreach($changes as $sock){

    //如果有新的client连接进来,则
    if($sock==$this->master){

      //接受一个socket连接
      $client=socket_accept($this->master);

      //给新连接进来的socket一个唯一的ID
      $key=uniqid();
      $this->sockets[]=$client; //将新连接进来的socket存进连接池
      $this->users[$key]=array(
        'socket'=>$client,//记录新连接进来client的socket信息
        'shou'=>false    //标志该socket资源没有完成握手
      );
    //否则1.为client断开socket连接,2.client发送信息
    }else{
      $len=0;
      $buffer='';
      //读取该socket的信息,注意:第二个参数是引用传参即接收数据,第三个参数是接收数据的长度
      do{
        $l=socket_recv($sock,0);
        $len+=$l;
        $buffer.=$buf;
      }while($l==1000);

      //根据socket在user池里面查找相应的$k,即健ID
      $k=$this->search($sock);

      //如果接收的信息长度小于7,则该client的socket为断开连接
      if($len<7){
        //给该client的socket进行断开操作,并在$this->sockets和$this->users里面进行删除
        $this->send2($k);
        continue;
      }
      //判断该socket是否已经握手
      if(!$this->users[$k]['shou']){
        //如果没有握手,则进行握手处理
        $this->woshou($k,$buffer);
      }else{
        //走到这里就是该client发送信息了,对接受到的信息进行uncode处理
        $buffer = $this->uncode($buffer,$k);
        if($buffer==false){
          continue;
        }
        //如果不为空,则进行消息推送操作
        $this->send($k,$buffer);
      }
    }
  }

}

}

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读