PHP之Socket伺服器搭建和測試執行個體分享

來源:互聯網
上載者:User
1.socket伺服器搭建思路

1) 目的:理解socket伺服器工作機制

2) 思路:建立socket -> 把socket加入串連池 -> 處理接收資訊 -> 握手動作 -> 發送資訊

2.socket伺服器代碼

註:複製到php檔案,直接命令列可以運行,不需要其他支援

特別注意:為了能傳輸中文_sendMsg做了json_encode()

<?php/** * Socket伺服器 * @author wuchangliang 2018/1/17 */class SocketServer{    private $sockets; //串連池    private $master;    private $handshake;    /**      * @param $address     * @param $port     */    public function run($address, $port)     {        //配置錯誤層級、已耗用時間、重新整理緩衝區          echo iconv('UTF-8', 'GBK', "歡迎來到PHP Socket測試服務。 \n");          error_reporting(0);          set_time_limit(0);          ob_implicit_flush();           //建立socket           $this->master = $this->_connect($address, $port);           $this->sockets[] = $this->master;            //運行socket        while (true)     {            $sockets = $this->sockets;                $write = NULL;            $except = NULL;                 socket_select($sockets, $write, $except, NULL);      //$write,$except傳引用                  foreach ($sockets as $socket) {                      if ($socket == $this->master) {                          $client = socket_accept($socket);                           $this->handshake = false;                           if ($client) {                               $this->sockets[] = $client; //加入串連池                           }                } else {                            //接收資訊                             $bytes = @socket_recv($socket, $buffer, 2048, 0);                              if ($bytes <= 6) {                                       $this->_disConnect($socket);                                        continue;                                      };                                       //處理資訊                                         if (!$this->handshake)                            {                                                   $this->_handshake($socket, $buffer);                                               } else {                                      $buffer = $this->_decode($buffer);                                   $this->_sendMsg($buffer, $socket);                           }                }            }        }    }       /**     * 建立socket串連     * @param $address     * @param $port     * @return resource     */                                  private function _connect($address, $port)    {        //建立socket         $master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)         or die("socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n");         socket_bind($master, $address, $port)        or die("socket_bind() failed: reason: " .  socket_strerror(socket_last_error($master)) . "\n");        socket_listen($master, 5)         or die("socket_listen() failed: reason: " . socket_strerror(socket_last_error($master)) . "\n");         return $master;    }    /**     * 握手動作     * @param $socket     * @param $buffer     */     private function _handshake($socket, $buffer)    {        //握手動作資訊         $buf = substr($buffer, strpos($buffer, '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($socket, $new_message, strlen($new_message));        $this->handshake = true;    }    /**     * 斷開socket串連     * @param $socket     */    private function _disConnect($socket)    {        $index = array_search($socket, $this->sockets);        socket_close($socket);        if ($index >= 0) {            array_splice($this->sockets, $index, 1);        }    }    /**     * 發送資訊     * @param $buffer     * @param $client     */    private function _sendMsg($buffer, $client)        {        $send_buffer = $this->_frame(json_encode($buffer));        foreach ($this->sockets as $socket) {            if ($socket != $this->master && $socket != $client) { //廣播發送(除了自己)                socket_write($socket, $send_buffer, strlen($send_buffer));                }        }    }    /**     * 解析資料幀         * @param $buffer     * @return null|string     */    private function _decode($buffer)    {        $len = $masks = $data = $decoded = null;            $len = ord($buffer[1]) & 127;        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;    }    /**     * 處理返回幀     * @param $buffer     * @return string     */    private function _frame($buffer)        {        $len = strlen($buffer);        if ($len <= 125) {            return "\x81" . chr($len) . $buffer;        } else if ($len <= 65535)     {            return "\x81" . chr(126) . pack("n", $len) . $buffer;        } else     {            return "\x81" . char(127) . pack("xxxxN", $len) . $buffer;        }    }}$sc = new SocketServer();$sc->run('127.0.0.1', 2046);

3.用戶端代碼

註:直接複製到html,和上面的php檔案在同一檔案夾即可,特別注意onmessage解析的兩層 parse

<!DOCTYPE html><html><head>    <meta charset="utf-8" />    <title>WebSocket Test</title>    <script language="javascript"type="text/javascript">        websocket = new WebSocket('ws://127.0.0.1:2046/');        websocket.onopen = function(evt) {            console.log('connect');            websocket.send('{"data":"您好,世界!"}');        };        websocket.onclose = function(evt) {            console.log('onclose');            console.log(evt);        };        websocket.onmessage = function(evt) {            console.log('onmessage');            if (evt.data) {                console.log(JSON.parse(JSON.parse(evt.data)));            }        };        websocket.onerror = function(evt) {            console.log('onerror');            console.log(evt);        };        function sendMsg(){            var sendData = { 'data': document.getElementById('name').value};            websocket.send(JSON.stringify(sendData));        }    </script></head><body>    <h2>WebSocket Test</h2>    <input type="text" name="name" id="name" />    <a href="javascript:;" onclick="sendMsg()">點擊發送</a></body></html>

4.測試樣本


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.