PHP使用socket实现聊天通讯

代码进行简单配置,能直接跑起来。直接上代码

class ws_socket{

  public $socket = null;     //服务端创建的socket

  public $sockts = [];        //连接池

  public $user= [];            //保存所有链接的用户

  public $write = null;       //socket_select第二个参数

  public $except = null;    //socket_select第三个参数  

  public function __construct($ip,$port){

    $this->socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);    //创建

    socket_set_option($this->socket,SOL_SOCKET,SO_REUSEADDR,true);    //设置

    socket_bind($this->socket,$ip,$port);                   //绑定

    socket_listen($this->socket);                         //监听

  }

  //用户连接开始聊天
  public function run(){
    $this->sockts[] = $this->socket;
    while(true){
      $tmp_sockets = $this->sockts;
      socket_select($tmp_sockets,$write,$except,null);   //关键函数,IO复用,多用户链接(1,2,3参数都是引用传值)

      foreach($tmp_sockets as $sock){
        if($sock==$this->socket){
          $conSock = socket_accept($this->socket);    //新用户,保存到连接池
          $this->sockts[] = $conSock;
          $this->user[] = ['socket'=>$conSock,'handshake'=>false];
        }else{
          
          $request = socket_read($sock,8024);       //接收用户消息
          $k = $this->getUserIndex($sock);       //找到当前发送用的在连接池的$k
          if(strlen($request)==8){            //用户退出 关闭该连接池
            $this->close($k);           //关闭当前关闭的链接
            continue;
          }
          //判断是否有握手,没有握手先握手,有握手直接发生消息
          if(!$this->user[$k]['handshake']){
            $response = $this->handleShake($request);
            socket_write($sock,$response,strlen($response));
            $this->user[$k]['handshake'] = true;
          }else{
            $msg = $this->decode($request);
            $jsonArr = json_decode($msg);
            $this->send($jsonArr,$k);
          }
        }
      }
    }
  }

  //关闭链接
  private function close($k){
    //找到关闭的链接 并在连接池删除
    socket_close($this->user[$k]['socket']);
    unset($this->user[$k]);
    //将连接池清空,再将user重新赋值给连接池
    $this->sockts = null;
    $this->sockts[] = $this->socket;
    foreach($this->user as $v){
      $this->sockts[] = $v['socket'];
    }
  }

  //获取用户的$k
  private function getUserIndex($sock){
    foreach($this->user as $k=>$v){
      if($v['socket']==$sock){
        return $k;
      }
    }
  }

  //编码函数
  private function encode($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);
  }

  //编码函数
  private function decode($buffer) {
    $decoded = '';
    if ( !empty($buffer[1]) ) {
      $len = ord($buffer[1]) & 127;
    }else{
      $len = '';
    }
    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++) {
      $decoded .= $data[$index] ^ $masks[$index % 4];
    }
    return $decoded;
  }

  //握手函数
  private function handleShake($request){
    $buf = substr($request,strpos($request,'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";
    return $new_message;
  }

  //发送消息,业务处理  $msg参数是客服端发送过来的信息
  private function send($msg,$k){

    //需要发送的数据

    $res['replyname'] = '小白';
    $res['replyid'] = 1;
    $res['msgtype'] = 2;
    $res['isline'] = '在线';
    $res = $this->encode(json_encode($res));

    socket_write($this->user[$k]['socket'],$res,strlen($res));    //发送

  }

}

$obj = new Ws(0,8888);
$obj->run();

后面会把webSocket的代码也分享出来,有什么问题评论留言

转载于:https://www.cnblogs.com/luoqinghui/p/10824283.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值