国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

PHP websocket之聊天室實現(xiàn)

wangbjun / 1775人閱讀

摘要:在服務(wù)器編程中函數(shù)把進程變?yōu)橐粋€服務(wù)器,并指定相應(yīng)的套接字變?yōu)楸粍舆B接其中的能存儲的請求不明的數(shù)目。

PHP部分

 [
     *                        info
     *                      ]
     *      ]
     *  todo 解釋socket與file號對應(yīng)
     */
    private $sockets = [];
    private $master;
    public function __construct($host, $port) {
        try {
            $this->master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            // 設(shè)置IP和端口重用,在重啟服務(wù)器后能重新使用此端口;
            socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1);
            // 將IP和端口綁定在服務(wù)器socket上;
            socket_bind($this->master, $host, $port);
            // listen函數(shù)使用主動連接套接口變?yōu)楸贿B接套接口,使得一個進程可以接受其它進程的請求,從而成為一個服務(wù)器進程。在TCP服務(wù)器編程中l(wèi)isten函數(shù)把進程變?yōu)橐粋€服務(wù)器,并指定相應(yīng)的套接字變?yōu)楸粍舆B接,其中的能存儲的請求不明的socket數(shù)目。
            socket_listen($this->master, self::LISTEN_SOCKET_NUM);
        } catch (Exception $e) {
            $err_code = socket_last_error();
            $err_msg = socket_strerror($err_code);
            $this->error([
                "error_init_server",
                $err_code,
                $err_msg
            ]);
        }
        $this->sockets[0] = ["resource" => $this->master];
        $pid = posix_getpid();
        $this->debug(["server: {$this->master} started,pid: {$pid}"]);
        while (true) {
            try {
                $this->doServer();
            } catch (Exception $e) {
                $this->error([
                    "error_do_server",
                    $e->getCode(),
                    $e->getMessage()
                ]);
            }
        }
    }
    private function doServer() {
        $write = $except = NULL;
        $sockets = array_column($this->sockets, "resource");
        $read_num = socket_select($sockets, $write, $except, NULL);
        // select作為監(jiān)視函數(shù),參數(shù)分別是(監(jiān)視可讀,可寫,異常,超時時間),返回可操作數(shù)目,出錯時返回false;
        if (false === $read_num) {
            $this->error([
                "error_select",
                $err_code = socket_last_error(),
                socket_strerror($err_code)
            ]);
            return;
        }
        foreach ($sockets as $socket) {
            // 如果可讀的是服務(wù)器socket,則處理連接邏輯
            if ($socket == $this->master) {
                $client = socket_accept($this->master);
                // 創(chuàng)建,綁定,監(jiān)聽后accept函數(shù)將會接受socket要來的連接,一旦有一個連接成功,將會返回一個新的socket資源用以交互,如果是一個多個連接的隊列,只會處理第一個,如果沒有連接的話,進程將會被阻塞,直到連接上.如果用set_socket_blocking或socket_set_noblock()設(shè)置了阻塞,會返回false;返回資源后,將會持續(xù)等待連接。
                if (false === $client) {
                    $this->error([
                        "err_accept",
                        $err_code = socket_last_error(),
                        socket_strerror($err_code)
                    ]);
                    continue;
                } else {
                    self::connect($client);
                    continue;
                }
            } else {
                // 如果可讀的是其他已連接socket,則讀取其數(shù)據(jù),并處理應(yīng)答邏輯
                $bytes = @socket_recv($socket, $buffer, 2048, 0);
                if ($bytes < 9) {
                    $recv_msg = $this->disconnect($socket);
                } else {
                    if (!$this->sockets[(int)$socket]["handshake"]) {
                        self::handShake($socket, $buffer);
                        continue;
                    } else {
                        $recv_msg = self::parse($buffer);
                    }
                }
                array_unshift($recv_msg, "receive_msg");
                $msg = self::dealMsg($socket, $recv_msg);
                $this->broadcast($msg);
            }
        }
    }
    /**
     * 將socket添加到已連接列表,但握手狀態(tài)留空;
     *
     * @param $socket
     */
    public function connect($socket) {
        socket_getpeername($socket, $ip, $port);
        $socket_info = [
            "resource" => $socket,
            "uname" => "",
            "handshake" => false,
            "ip" => $ip,
            "port" => $port,
        ];
        $this->sockets[(int)$socket] = $socket_info;
        $this->debug(array_merge(["socket_connect"], $socket_info));
    }
    /**
     * 客戶端關(guān)閉連接
     *
     * @param $socket
     *
     * @return array
     */
    private function disconnect($socket) {
        $recv_msg = [
            "type" => "logout",
            "content" => $this->sockets[(int)$socket]["uname"],
        ];
        unset($this->sockets[(int)$socket]);
        return $recv_msg;
    }
    /**
     * 用公共握手算法握手
     *
     * @param $socket
     * @param $buffer
     *
     * @return bool
     */
    public function handShake($socket, $buffer) {
        // 獲取到客戶端的升級密匙
        $line_with_key = substr($buffer, strpos($buffer, "Sec-WebSocket-Key:") + 18);
        $key = trim(substr($line_with_key, 0, strpos($line_with_key, "
")));
        // 生成升級密匙,并拼接websocket升級頭
        $upgrade_key = base64_encode(sha1($key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));// 升級key的算法
        $upgrade_message = "HTTP/1.1 101 Switching Protocols
";
        $upgrade_message .= "Upgrade: websocket
";
        $upgrade_message .= "Sec-WebSocket-Version: 13
";
        $upgrade_message .= "Connection: Upgrade
";
        $upgrade_message .= "Sec-WebSocket-Accept:" . $upgrade_key . "

";
        socket_write($socket, $upgrade_message, strlen($upgrade_message));// 向socket里寫入升級信息
        $this->sockets[(int)$socket]["handshake"] = true;
        socket_getpeername($socket, $ip, $port);
        $this->debug([
            "hand_shake",
            $socket,
            $ip,
            $port
        ]);
        // 向客戶端發(fā)送握手成功消息,以觸發(fā)客戶端發(fā)送用戶名動作;
        $msg = [
            "type" => "handshake",
            "content" => "done",
        ];
        $msg = $this->build(json_encode($msg));
        socket_write($socket, $msg, strlen($msg));
        return true;
    }
    /**
     * 解析數(shù)據(jù)
     *
     * @param $buffer
     *
     * @return bool|string
     */
    private function parse($buffer) {
        $decoded = "";
        $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 json_decode($decoded, true);
    }
    /**
     * 將普通信息組裝成websocket數(shù)據(jù)幀
     *
     * @param $msg
     *
     * @return string
     */
    private function build($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);
    }
    /**
     * 拼裝信息
     *
     * @param $socket
     * @param $recv_msg
     *          [
     *          "type"=>user/login
     *          "content"=>content
     *          ]
     *
     * @return string
     */
    private function dealMsg($socket, $recv_msg) {
        $msg_type = $recv_msg["type"];
        $msg_content = $recv_msg["content"];
        $response = [];
        switch ($msg_type) {
            case "login":
                $this->sockets[(int)$socket]["uname"] = $msg_content;
                // 取得最新的名字記錄
                $user_list = array_column($this->sockets, "uname");
                $response["type"] = "login";
                $response["content"] = $msg_content;
                $response["user_list"] = $user_list;
                break;
            case "logout":
                $user_list = array_column($this->sockets, "uname");
                $response["type"] = "logout";
                $response["content"] = $msg_content;
                $response["user_list"] = $user_list;
                break;
            case "user":
                $uname = $this->sockets[(int)$socket]["uname"];
                $response["type"] = "user";
                $response["from"] = $uname;
                $response["content"] = $msg_content;
                break;
        }
        return $this->build(json_encode($response));
    }
    /**
     * 廣播消息
     *
     * @param $data
     */
    private function broadcast($data) {
        foreach ($this->sockets as $socket) {
            if ($socket["resource"] == $this->master) {
                continue;
            }
            socket_write($socket["resource"], $data, strlen($data));
        }
    }
    /**
     * 記錄debug信息
     *
     * @param array $info
     */
    private function debug(array $info) {
        $time = date("Y-m-d H:i:s");
        array_unshift($info, $time);
        $info = array_map("json_encode", $info);
        file_put_contents(self::LOG_PATH . "websocket_debug.log", implode(" | ", $info) . "
", FILE_APPEND);
    }
    /**
     * 記錄錯誤信息
     *
     * @param array $info
     */
    private function error(array $info) {
        $time = date("Y-m-d H:i:s");
        array_unshift($info, $time);
        $info = array_map("json_encode", $info);
        file_put_contents(self::LOG_PATH . "websocket_error.log", implode(" | ", $info) . "
", FILE_APPEND);
    }
}
$ws = new WebSocket("127.0.0.1", "8080");

HTML部分




    
    
    


websocket聊天室

當前在線:0



文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/29256.html

相關(guān)文章

  • PHP websocket天室實現(xiàn)

    摘要:在服務(wù)器編程中函數(shù)把進程變?yōu)橐粋€服務(wù)器,并指定相應(yīng)的套接字變?yōu)楸粍舆B接其中的能存儲的請求不明的數(shù)目。 PHP部分

    weknow619 評論0 收藏0
  • PHP websocket天室實現(xiàn)

    摘要:在服務(wù)器編程中函數(shù)把進程變?yōu)橐粋€服務(wù)器,并指定相應(yīng)的套接字變?yōu)楸粍舆B接其中的能存儲的請求不明的數(shù)目。 PHP部分

    mo0n1andin 評論0 收藏0
  • Websocket解析及實現(xiàn)

    摘要:早期的輪詢是通過不斷自動刷新頁面而實現(xiàn)的。長輪詢的另一個問題是缺乏標準實現(xiàn)。服務(wù)器端接到這個請求后作出回應(yīng)并不斷更新連接狀態(tài)以保證客戶端和服務(wù)器端的連接不過期。協(xié)議解析協(xié)議包含兩部分一部分是握手,一部分是數(shù)據(jù)傳輸。 Websocket是什么? Websocket是一個因為應(yīng)用場景越來越復(fù)雜而提出的,針對瀏覽器和web服務(wù)器之間雙向持續(xù)通信而設(shè)計,而且優(yōu)雅地兼容HTTP的協(xié)議(我猜想:同...

    XboxYan 評論0 收藏0
  • 實戰(zhàn) swoole【天室

    摘要:是一個請求對象,包含了客戶端發(fā)來的握手請求信息事件函數(shù)中可以調(diào)用向客戶端發(fā)送數(shù)據(jù)或者調(diào)用關(guān)閉連接事件回調(diào)是可選的當服務(wù)器收到來自客戶端的數(shù)據(jù)幀時會回調(diào)此函數(shù)。 前言:了解概念之后就應(yīng)該練練手啦,不然就是巨嬰 有收獲的話請加顆小星星,沒有收獲的話可以 反對 沒有幫助 舉報三連 代碼倉庫 實戰(zhàn)swoole【聊天室】 在線體驗 準備工作 需要先看初識swoole【上】,了解基本的服務(wù)端...

    andycall 評論0 收藏0
  • 簡單又好用的天室技術(shù)——WebSocket

    摘要:國際慣例,先上維基百科的解釋。維基百科上面是維基百科對的解釋,別問我如何解釋上面這段話,因為我也沒看懂,那么下面我用人話解釋一下吧僅僅是我的理解是一個協(xié)議,可以簡單看成是協(xié)議的一個補充協(xié)議,借助協(xié)議的基礎(chǔ)完成服務(wù)器主動與客戶端實時傳輸數(shù)據(jù)。 現(xiàn)在,很多網(wǎng)站為了實現(xiàn)推送技術(shù),所用的技術(shù)都是輪詢。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務(wù)器發(fā)出HTTP request,然后由服務(wù)...

    Prasanta 評論0 收藏0

發(fā)表評論

0條評論

wangbjun

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<