>  기사  >  백엔드 개발  >  웹소켓을 기반으로 채팅방을 구축하는 PHP 실습

웹소켓을 기반으로 채팅방을 구축하는 PHP 실습

墨辰丷
墨辰丷원래의
2018-05-31 10:43:217188검색

이 글은 주로 php+websocket을 사용하여 간단한 채팅방을 구축하는 실습을 설명합니다. 필요하신 분들은 글의 php와 websocket 내용을 참고하시기 바랍니다.

이 문서의 예에서는 웹소켓을 기반으로 PHP로 간단한 채팅방을 구축하는 방법을 설명합니다. 참고할 수 있도록 모든 사람과 공유하세요.
1. 서문

회사 게임에 간단한 채팅방이 있다는 걸 이해하고 보니, node+websocket으로 만든 줄 알았습니다. 방. 그래서 다양한 정보를 수집하고, 문서를 읽고, 사례를 찾아보고, 간단한 채팅방을 직접 작성했습니다.

http 연결은 짧은 연결과 긴 연결로 구분됩니다. 짧은 연결은 일반적으로 ajax를 사용하여 구현할 수 있으며 긴 연결은 웹소켓입니다. 짧은 연결은 비교적 구현이 간단하지만 너무 많은 리소스를 소비합니다. Websocket은 효율적이지만 호환성에 몇 가지 문제가 있습니다. Websocket은 html5

2의 리소스입니다. Front-end

front-end는 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을 구현하는 것이 매우 간단하고 간단합니다. 백엔드

3.1 websocket 연결 프로세스

websocket 통신 다이어그램 이것은 클라이언트와 서버 간의 간단한 통신 다이어그램입니다. PHP가 주로 하는 일은 암호화 키를 수락하고 이를 반환하여 소켓 생성 및 핸드셰이크 작업을 완료하는 것입니다



아래 사진은 최종적으로 웹소켓 처리의 세부 서비스 흐름도입니다.


3.2 코드 연습

서버에서 수행되는 프로세스는 대략 다음과 같습니다.


연결을 기다리는 소켓 소켓 프로세스를 걸어 놓습니다.

  1. 소켓 연결이 이루어진 후 소켓을 탐색합니다. 인터페이스 배열

  2. 핸드셰이크가 없으면 데이터가 구문 분석되어 출력을 위해 버퍼에 기록됩니다.


  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);
            //如果接收的字节是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. 웹소켓 콘텐츠를 수신하고 Sec-WebSocket-Key에서 키를 얻으려면: 그리고 통과 버퍼에 기록된 암호화 알고리즘은 클라이언트에 의해 확인됩니다(자동 확인에는 처리가 필요하지 않습니다)

public function hands($client,$buff,$v)
    {
      //提取websocket传的key并进行加密 (这是固定的握手机制获取Sec-WebSocket-Key:里面的key)
      $buf = substr($buff,strpos($buff,&#39;Sec-WebSocket-Key:&#39;)+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 = &#39;&#39;; 
      $msg = unpack(&#39;H*&#39;,$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(
            &#39;mess&#39;=>$block[0],
            );
        return $mess;          
      }

6. 소켓을 버퍼에 씁니다

//发送数据
    public function send($mess,$v)
    {
      //遍历套接字数组 成功握手的 进行数据群发
      foreach ($this->socs as $keys => $values) {
        //用系统分配的套接字资源id作为用户昵称
          $mess[&#39;name&#39;]="Tourist&#39;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 창에서 경로를 구성하십시오)

php -f server.php

오류가 있으면

이라는 메시지가 표시됩니다. ②서버를 통해 html 파일에 액세스

8. 피트를 밟았다면 디버깅 작업을 열어서 오류를 쉽게 확인할 수 있습니다

①server.php 중단된 프로세스를 인쇄할 수 있습니다. 네, 문제가 있으면 코드에 인쇄를 추가할 수 있습니다. 디버깅을 위해

각 판단을 표시하고 코드가 실행 중인 섹션을 콘솔에서 확인할 수 있습니다

하지만 코드를 수정한 후 매번 php server.php 스크립트를 다시 실행해야 합니다

②이 오류가 발생하면 be

1. 서버와 소켓 초기화 시 데이터 보내기(서버와의 첫 번째 확인 핸드셰이크 중에는 콘텐츠를 보낼 수 없음)

2. 확인된 경우에도 이러한 상황이 발생합니다. 보내지 않거나 보낸 메시지가 비어 있으므로 연결된 소켓의 데이터를 확인해야합니다. 확인이 잘되었습니다

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

이상이 이 글의 전체 내용이므로 모든 분들의 학습에 도움이 되기를 바랍니다. .

관련 추천:

PHP 무작위 빨간 봉투 알고리즘에 대한 자세한 설명

PHP를 사용하여 주변 사람 검색


PHP 긴 연결 사용 사례 분석

위 내용은 웹소켓을 기반으로 채팅방을 구축하는 PHP 실습의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.