<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## s-socket ```php <?php /** * 學習 tcp/ip socket 能夠讓你了解計算機網絡是如何工作的,掌握它就是掌握了進入互聯網的鑰匙 * 熟練掌握計算機網絡原理能夠讓你的技術上一個新的臺階,而不再只局限于應用層的CURD了 * socket 是計算機程序通信的基礎,有了套接字,不同的程序和不同的計算機就能夠相互通信 * 從此站在底層看上層應用就會有一覽眾山小的感覺,如 redis mysql pdo ,http 請求、響應是什么原理? * 平時在業務中使用時有沒有想過它們背后是怎么工作的呢,性能瓶頸在哪里呢? * 從底層去看,這些都了無秘密,這樣優化上層應用的性能問題就很容易了,對各種眼花繚亂的中間件也不會再覺得望而生畏了 * 不過最為重要的是,學習這些設計背后的思想,思考為什么這樣設計,并逐漸理解軟件設計過程中的難處,以及如何平衡和取舍 * 最后忘記你學到的全部內容,剩下的就是你真正學會的了 */ /** * socket 五步曲 * 1. 創建 * 2. 綁定 * 3. 監聽 * 4. 接受 * 5. 收發 */ // cmd: telnet 127.0.0.1 5000 function getSockErrorCode($sock = null) { return $sock ? socket_last_error($sock) : socket_last_error(); } function getSockError($sock = null) { $code = getSockErrorCode($sock); if ($code > 0) { } else { return ''; } $msg = socket_strerror($code); $msg = iconv("GBK", "utf-8", $msg); return "socket error: [{$code}] {$msg}"; } /** * 創建一個套接字資源 * 1. 規定了:通訊協議域簇、套接字類型、傳輸協議 */ $server_sock = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); /** * 為套接字綁定一個端口 * * 1. 默認情況一個端口只能被一個進程綁定,重復綁定會報端口被占用的錯誤 * 2. 如果 內核支持 so_reuseport 參數時就可以實現多個進程綁定同一個端口 * socket_set_option($server_sock, SOL_SOCKET, 'so_reuseport', 1); * * https://blog.csdn.net/u010565545/article/details/99244959 * 127.0.0.1 本地回環地址(之一),本機ip,虛擬網卡的ip,如果你不知道本地外網ip的話就用這個 * 0.0.0.0 所有 本機ip */ socket_bind($server_sock, '127.0.0.1', 2347); /** * 開始監聽此套接字 */ socket_listen($server_sock); /** * 套接字操作:連接、接受、接收、發送...... * * 當一個操作在一個阻塞的套接字上執行時,腳本將暫停執行,直到它收到一個信號或者它可以執行該操作。 * * socket_set_nonblock() 函數在由socket參數指定的socket上設置 O_NONBLOCK 標志。 * socket_set_block() 函數刪除了由socket參數指定的套接字上的 O_NONBLOCK 標志。 * * 阻塞的 socket 上: * 1. 在套接字上進行操作時會被阻塞,直到收到信號或可操作時才會執行該操作 * 2. 信號即 socket 收到操作系統的信號,表示可以進行 可讀、可寫 等操作了 * 3. 套接字默認是阻塞模式的 * * 非阻塞的 socket 上: * 1. 在套接字上進行操作時不會被阻塞,但不一定調用成功 * 2. 只有在收到信號或可操作時才能執行該套接字操作,否則會導致調用失敗,返回 false * 3. 注意,非阻塞會使阻塞性質(原本會導致阻塞)的套接字操作調用失敗,返回 false * 所以需要判斷當返回 false 時屬于哪種情況,真有錯,還是 非阻塞模式時調用了會導致阻塞的套接字操作 * */ // socket_set_nonblock($server_sock); // 將 server_sock 設為非阻塞 /* * 接受一個客戶端的連接(每次接受一個客戶端連接,返回值為一個 客戶端 socket) * * 1. 可能會阻塞,取決于 server_sock 是否為阻塞的 * 2. 它會阻塞在等待客戶端的連接上,直到有新的客戶端連接 * 3. 如果該套接字上有多個排隊的連接,將使用第一個。如果沒有待處理的連接,socket_accept()將阻塞 * 4. 為非阻塞模式時,在沒有客戶端連接時,立即返回 false,所以非阻塞模式 應該使用 socket_select * 5. 返回 false 可能是 客戶端 socket 已關閉等原因,也有可能是 非阻塞模式下 連接隊列為空時,需要使用 socket_last_error socket_strerror 來判斷具體情況(socket error: [10035] 無法立即完成一個非阻止性套接字操作。) * 6. 返回的 socket 實例不能被用來接受新的連接 */ $client_sock = socket_accept($server_sock); // echo getSockError($server_sock); // var_dump($client_sock);exit; // 客戶端sock 還可以設置非阻塞 socket_set_nonblock($client_sock); /** * 從客戶端 socket 上讀取數據 * * 1. 可能會阻塞,取決于 server_sock 是否為阻塞的 * 2. 它會阻塞在讀取內核 socket 可讀緩沖區上,直到有可讀數據,可讀時返回讀取到的數據 * 3. 為非阻塞模式時,在沒有可讀數據時,立即返回 false,有可讀數據時,返回讀取到的數據 * 4. 可設置每次最大讀取字節,當然最終取決于實際可讀的內容長度,或者也可以使用第三個參數 每次 \r, \n, \0 時結束 * 5. 建議設置最大讀取長度,以控制每次從內核讀取數據的大小,使內存消耗在可控范圍內(建議 65535 一個數據包 最大的數據部分長度) * 6. 在讀取錯誤時返回 false(并且會報錯 Warning) 這可能是 客戶端 socket 已關閉等原因,可使用 socket_last_error socket_strerror 來獲取錯誤信息 * 7. 阻塞模式時,如果返回空串,可能時遠端報錯了,不可再讀了 * * 同樣的,返回 false 時要注意判斷:socket error: [10035] 無法立即完成一個非阻止性套接字操作。 * * 可讀嗎,可讀,但只能讀一點點 */ // $buf = socket_read($client_sock, 1024); // echo getSockError($client_sock); // var_dump($buf);exit; socket_clear_error($client_sock); // socket_set_nonblock($client_sock); $msg = 'you input: ' . $buf; // socket_set_option($client_sock, SOL_SOCKET, SO_SNDBUF, 2); // // 65536 // $sndbuf = socket_get_option($client_sock, SOL_SOCKET, SO_SNDBUF); // echo 'sndbuf: ' . $sndbuf . PHP_EOL; $msg = str_repeat($msg, 1000000) . PHP_EOL . 'xiaobu' . PHP_EOL; echo 'msg len: ' . strlen($msg) . PHP_EOL; /** * 往客戶端 socket 上寫入數據 * * 1. 可能會阻塞,取決于 server_sock 是否為阻塞的 * 2. 它會阻塞在寫入內核 socket 寫入緩沖區上,直到有可寫入空間 * 3. 為非阻塞模式時,在沒有可寫入空間時,立即返回 0或 false,可寫入時,返回實際寫入的數據字節數 * 4. 可設置每次最大寫入字節,當然最終寫入數據長度取決于緩沖區大小 * 5. 建議設置最大寫入長度為要寫入的內容長度,期望是能一次寫入完畢 * 6. 在寫入錯誤時 返回 返回 false 這可能是 客戶端 socket 已關閉等原因,可使用 socket_last_error socket_strerror 來獲取錯誤信息 * * socket_write()不一定會寫入給定緩沖區中的所有字節。根據網絡緩沖區等情況,雖然你的緩沖區更大,但只有一定數量的數據,甚至一個字節被寫入,這是有效的。你必須注意,以免你無意中忘記傳輸其余的數據。 * * 可寫嗎,可寫,但只能寫一點點 */ $l = socket_write($client_sock, $msg, strlen($msg)); // 也可能阻塞,或者根本沒有完全寫完數據 echo getSockError($client_sock); var_dump($l); sleep(3); exit; /** * 與此客戶端斷開連接,通常是業務交互完畢了,并且不需要保持長連接 */ socket_close($client_sock); /** * 關閉服務端 socket,結束服務,這意味著服務關閉,通常在關閉服務器時才會這么做 */ socket_close($server_sock); // ================================= // 上面這樣 很多操作是阻塞的,并且操作不是一次能完成的,這樣寫起來很麻煩 // 1. 如果能監聽 socket 何時可操作就好了 // 2. 如果能知曉 一個 socket 何時可操作,提前將 操作設置成回調,這就是事件了 // 3. 如果不斷的監聽,并觸發回調,就是事件循環了 // 監聽 socket 狀態 // socket_select( array|null &$read, array|null &$write, array|null &$except, int|null $seconds, int $microseconds = 0) : int|false $read = $write = $except = [$client_sock]; $ret = socket_select($read, $write, $except, 1, 0); // 打斷一下,先拋出兩個問題,慢慢思考 // 1. 客戶端 與 服務端 收發數據的長度是不可控的,怎么判斷收到了一個完整的內容呢,這就是粘包問題 // 答:每個內容末尾加一個特殊標記位,如 末尾\n,或者如 http 協議中的 Content-Length: xx 來確定內容長度進行區分 // 2. http 協議 如何 確定 請求-響應 之間的對應關系呢? // 答:有可能多個請求和響應是連續的,且順序不可預測,那么只能通過請求標記與響應標記來確定關聯性了 // 但是 http 協議沒有規定這方面的內容,現在是由 瀏覽器實現的:要復用 tcp連接 只能一個 請求-響應 完畢才會發送第二個請求 // 所以也就不存在這個問題了。 // https://www.cnblogs.com/everlose/p/12779773.html // https://zhuanlan.zhihu.com/p/29609078 http2 才支持這個功能 // 3. 一個連接上能同時交替發送兩個內容嗎? // 答:不能,除非自己實現幀數據協議。沒必要實現這樣的功能,沒意義,與其兩個包都不能快點發送完,還不如早點讓一個包發送完 // 感想:客戶端的情況要簡單些(雖然也可以做的復雜,但沒必要只是徒增煩惱),因為不像服務端一樣要考慮為多人服務(不能使用阻塞),所以可以粗暴一些,這樣能簡化和避免很多問題。如 可以使用阻塞的方式收發消息 // 這樣減少了復雜度,更容易實現也更穩定。如 直接避免了并發交替發送數據包的情況。 // 客戶端編碼習慣了同步阻塞的方式,這樣開發更簡單直觀,試想 你寫的 curd 不都是同步操作 mysql 的 // onRead: 一次可讀信號 // onMessage: 一個完整的消息內容接收完畢 // onWrite: 一次可寫信號 // onSend: 一個完整的消息內容發送完畢 // ========================== // https://blog.csdn.net/wangjiben/article/details/40679587?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-4.no_search_link&spm=1001.2101.3001.4242.3 // 計算信息緩沖區大小 // Calculate message buffer size // socket_cmsg_space() // 向連接的套接字發送數據(數據已從緩沖區發出才返回) // Sends data to a connected socket // socket_send( Socket $socket, string $data, int $length, int $flags) : int|false // 向一個套接字發送消息,無論它是否連接。 // Sends a message to a socket, whether it is connected or not // socket_sendto( Socket $socket, string $data, int $length, int $flags, string $address, int|null $port = null) : int|false // 發送消息 // socket_sendmsg( Socket $socket, array $message, int $flags = 0) : int|false // 寫入一個套接字 寫到緩沖區(數據可能還沒被網卡發出去) // Write to a socket // socket_write( Socket $socket, string $data, int|null $length = null) : int|false // ---- // 從一個套接字中讀取最大長度的字節 // Reads a maximum of length bytes from a socket // socket_read( Socket $socket, int $length, int $mode = PHP_BINARY_READ) : string|false // 從已連接的socket接收數據 // 與 socket_read 類似 但可以 使用參數 flags 控制函數功能,如 指定至少讀到某個字節長度,和 “重復讀” // socket_recv( resource $socket, string &$buf, int $len, int $flags) : int // 從一個套接字接收數據,無論它是否面向連接。同 socket_recv 類似 // Receives data from a socket whether or not it is connection-oriented // socket_recvfrom( Socket $socket, string &$data, int $length, int $flags, string &$address, int &$port = null) : int|false // 讀取消息 // Read a message // socket_recvmsg( Socket $socket, array &$message, int $flags = 0) : int|false // 讀寫超時控制 任何時候超時控制都是必不可少的,并且要特別小心 feof 之類的可能會陷入無限循環的情況 // https://blog.csdn.net/q1007729991/article/details/71078044 // stream_set_timeout // socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>$sec, 'usec'=>$usec)); // socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec'=>$sec, 'usec'=>$usec)); // 關閉一個套接字的接收、發送或兩者都關閉。 // 相關的一個或多個緩沖區可能被清空,也可能不被清空。 // Shuts down a socket for receiving, sending, or both // socket_shutdown( Socket $socket, int $mode = 2) : bool // 服務端 // socket_write // socket_read // 客戶端 // socket_send // socket_sendto // socket_sendmsg // socket_write // socket_read // socket_recv // socket_recvfrom // socket_recvmsg // https://blog.csdn.net/csdn_zhang99/article/details/81669793 // 異步架構程序設計原則 // 1、回調函數不可以執行過長時間,因為一個loop中可能包含其他事件,尤其是會影響一些準確度要求比較高的timer。 // 2、盡量采用庫中所緩存的時間,有時候需要根據時間差來執行timeout之類的操作。當然能夠利用庫中的timer最好。 // 任務不要做復雜的事,不要在io上阻塞 ``` ---- [TCP-IP協議 · php筆記 · 看云](http://www.hmoore.net/xiak/php-node/2545482) > 接收方 read buffer 滿(說明應用程序處理能力過載),**不再接受數據, 不 ack 了,那么 發送方 write buffer 很快也就滿了(等不到 ack 就不刪除 write buffer)**,不能再發了。這算是一種 常規的TCP擁塞控制。 [libev_大張-CSDN博客_libev](https://blog.csdn.net/csdn_zhang99/article/details/81669793 ) ~~~ 異步架構程序設計原則 1、回調函數不可以執行過長時間,因為一個loop中可能包含其他事件,尤其是會影響一些準確度要求比較高的timer。 2、盡量采用庫中所緩存的時間,有時候需要根據時間差來執行timeout之類的操作。當然能夠利用庫中的timer最好。 任務不要做復雜的事,不要在io上阻塞 ~~~ [HTTP 的前世今生:一次性搞懂 HTTP、HTTPS、SPDY、HTT_請求](https://www.sohu.com/a/275505518_497161) > SPDY 引入了一個新的二進制分幀數據層,以實現多向請求和響應、優先次序、最小化及消除不必要的網絡延遲,目的是更有效地利用底層 TCP 連接。 [ReactPHP: Event-driven, non-blocking I/O with PHP - ReactPHP](https://reactphp.org/) > ReactPHP is non-blocking by default. Use workers for blocking I/O. > 大量的連接復用少數的進程,socket fd 事件循環是非阻塞的,但是 工人進程處理業務的部分是阻塞的。 [The Illustrated QUIC Connection: Every Byte Explained](https://quic.xargs.org/) [圖解 QUIC](https://cangsdarm.github.io/illustrate/quic)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看