首頁 >後端開發 >php教程 >如何使用php websocket建立簡單聊天室

如何使用php websocket建立簡單聊天室

伊谢尔伦
伊谢尔伦原創
2017-05-24 11:33:252526瀏覽

socket就是應用層與TCP/IP協定族通訊的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協定族隱藏在Socket介面後面,對使用者來說,一組簡單的介面就是全部,讓Socket去組織數據,以符合指定的協定.前面的章節我們談到了socket和http的區別,要理解socket就要先理解http和tcp的區別,簡單說就是一個是短鏈,一個是長鏈,一個是去伺服器拉數據,一個是伺服器可以主動推數據。 http連接分為短連接和長連接。短連線一般可以用ajax實現,長連線就是websocket。短連線實作起來比較簡單,但太過於消耗資源。 websocket高效不過相容存在點問題。 websocket是html5的資源。

php websocket創建簡單聊天室流程介紹

#php聊天室以前做時都是透過ajax與PHP來實現的,今天我們就一起來看一個PHP聊天室WebSocket技術實戰範例.

1. 前台客戶端

前台文件如何發送訊息到後台伺服器呢,後來研究發現是用的js 的WebSocket技術,如下是常用js WebSocket 常用操作:

其程式碼如下:

var socket = new WebSocket('ws://localhost:8080');     
    // 打开Socket     
    socket.onopen = function(event) {     
    }    
    // 发送一个初始化消息    
     socket.send('I am the client and I\'m listening!');     
    // 监听消息    
     socket.onmessage = function(event) {     
        console.log('Client received a message',event);     
      };  //phpfensi.com    
    // 监听Socket的关闭    
      socket.onclose = function(event) {     
        console.log('Client notified socket has closed',event);     
      };     
      // 关闭Socket....     
    socket.close()     
   socket.onerror = function(evt){console.log(“WebSocketError!”);};

說明:第一行會向指定伺服器發送一個握手請求,如果伺服器傳回合法的http頭,則握手成功,之後可透過監聽onmessage事件來處理伺服器發送的訊息。還有很多其他事件可監聽,見前面的url。

2.  後台服務端

服務端所做的流程大致是:

a. 掛起一個socket套接字進程等待連線

b. 有socket連線之後遍歷套接字陣列

c. 沒有握手的進行握手操作,如果已經握手則接收資料解析並寫入緩衝區進行輸出

範例程式碼如下:

public function start_server(){
  $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  //允许使用本地地址
  socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, TRUE);
  socket_bind($this->socket, $this->host, $this->port);
  //最多10个人连接,超过的客户端连接会返回WSAECONNREFUSED错误
  socket_listen($this->socket, $this->maxuser);
  while(TRUE) {
    $this->cycle = $this->accept;
    $this->cycle[] = $this->socket;
    //阻塞用,有新连接时才会结束
    socket_select($this->cycle, $write, $except, null);
    foreach ($this->cycle as $k => $v) {
      if($v === $this->socket) {
        if (($accept = socket_accept($v)) < 0) {
          continue;
        }
        //如果请求来自监听端口那个套接字,则创建一个新的套接字用于通信
        $this->add_accept($accept);
        continue;
      }
      $index = array_search($v, $this->accept);
      if ($index === NULL) {
        continue;
      }
      //没消息的socket就跳过
      if (!@socket_recv($v, $data, 1024, 0) || !$data) {
        $this->close($v);
        continue;
      }
      if (!$this->isHand[$index]) {
        $this->upgrade($v, $data, $index);
        if(!empty($this->function[&#39;add&#39;])) {
          call_user_func_array($this->function[&#39;add&#39;], array($this));
        }
        continue;
      }
      $data = $this->decode($data);
      if(!empty($this->function[&#39;send&#39;])) {
        call_user_func_array($this->function[&#39;send&#39;], array($data, $index, $this));
      }
    }
    sleep(1);
  }
}
//增加一个初次连接的用户
public function add_accept($accept){
  $this->accept[] = $accept;
  $index = array_keys($this->accept);
  $index = end($index);
  $this->isHand[$index] = FALSE;
}
//关闭一个连接
public function close($accept) {
  $index = array_search($accept, $this->accept);
  socket_close($accept);
  unset($this->accept[$index]);
  unset($this->isHand[$index]);
  if(!empty($this->function[&#39;close&#39;])) {
    call_user_func_array($this->function[&#39;close&#39;], array($this));
  }
}
//响应升级协议
public function upgrade($accept, $data, $index) {
  if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/",$data,$match)) {
    $key = base64_encode(sha1($match[1] . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;, true));
    $upgrade  = "HTTP/1.1 101 Switching Protocol\r\n" .
      "Upgrade: websocket\r\n" .
      "Connection: Upgrade\r\n" .
      "Sec-WebSocket-Accept: " . $key . "\r\n\r\n";  //必须以两个回车结尾
    socket_write($accept, $upgrade, strlen($upgrade));
    $this->isHand[$index] = TRUE;
  }
}

說明:關鍵地方有那麼幾個,一是while(true)掛起進程,不然執行一次後進程就退出了。二是socket_select和socket_accept函式的使用。三是客戶端第一次要求時握手。

後面的流程就很清楚了,當有一個新的客戶端請求到達,用socket_accept創建一個資源,並加入到$this->accept連接池裡面。並將它的標示isHand設為false,那麼下次迴圈(因為$this->cycle[] = $this->socket;$this->cycle有變化,所以socket_select會回傳)的時候就會執行upgrade握手。然後等待它的新訊息即可。

【相關教學推薦】

1. 《php.cn獨孤九賤(4)-php影片教學

2.   # #php程式設計從入門到精通全套教學

###

以上是如何使用php websocket建立簡單聊天室的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn