TCP 的連線建立與關閉狀態及資料傳輸通訊過程【含有 PHP socket API 測試實驗程式碼】

2020-07-16 10:05:44
本文章使用 PHP 程式碼來測試 TCP 傳輸層的一個通訊過程.

TCP/IP 協定

關於該協定的詳細內容可自行查閱 <<TCP/IP 詳解 捲 1:協定>>

PHP 的 tcp/udp API 內容是 PHP 手冊上的內容

socket API

測試的 PHP 版本

TCP的連線建立與關閉狀態及資料傳輸通訊過程

PHP 程式碼 【就是手冊的例子了】

 <?php
/**
 * Created by PhpStorm.
 * User: [email protected]
 * Date: 2019/6/19
 * Time: 9:55
 */
error_reporting(E_ALL);
/* Allow the script to hang around waiting for connections. */
set_time_limit(0);
/* Turn on implicit output flushing so we see what we're getting
 * as it comes in. */
ob_implicit_flush();
$address = '0.0.0.0';  //要監聽的ip地址
$port = 54321;//要監聽的埠 
//建立一個socket AF_INET是一個協定族 (一般都有AF_INET,AF_INET6,AF_UNIX c語言提供也是,只不過是地址族),而PHP叫網路協定  
//C語言提供的協定族是PF_INET,PF_INET6,PF_UNIX  
//SOCK_STREAM sock的服務型別  這裡是位元組流的服務型別用於TCP
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "n";
}
//socket選項  ,選項一般在socket建立後設定 用於設定TCP的連線屬性
//選項幾乎和c差不多一樣
//一般來說這些選項我們可以通過修改系統核心來調整 
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1)) {
    echo 'Unable to set option on socket: '. socket_strerror(socket_last_error()) . PHP_EOL;
}
if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEPORT, 1)) {
    echo 'Unable to set option on socket: '. socket_strerror(socket_last_error()) . PHP_EOL;
}
//係結【有的叫命名socket】
if (socket_bind($sock, $address, $port) === false) {
    echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "n";
}
//監聽 此時伺服器進入  LISTEN狀態
if (socket_listen($sock, 5) === false) {
    echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "n";
}
do {
//接受用戶端連線sock  從系統核心接受佇列裡取  如果取出則雙方進入了ESTABLISHED狀態
    if (($msgsock = socket_accept($sock)) === false) {
        echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "n";
        break;
    }
    /* Send instructions. */
    $msg = "nWelcome to the PHP Test Server. n" .
        "To quit, type 'quit'. To shut down the server type 'shutdown'.n";
    socket_write($msgsock, $msg, strlen($msg));
    do {
    //讀用戶端資料【從TCP接收接受緩衝區取】
        if (false === ($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ))) {
            echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "n";
            break 2;
        }
        if (!$buf = trim($buf)) {
            continue;
        }
        if ($buf == 'quit') {
            break;
        }
        if ($buf == 'shutdown') {
        //傳送FIN結束報文,正常情況伺服器會進入CLOSED狀態
            socket_close($msgsock);
            break 2;
        }
        $talkback = "PHP: You said '$buf'.n";
        socket_write($msgsock, $talkback, strlen($talkback));
        echo "$bufn";
    } while (true);
    socket_close($msgsock);
} while (true);
socket_close($sock);

socket 服務型別

680c44b6dc520fef26e495bb4615926.png

TCP/IP 選項檔案

b712e6f7f12a36d2a6e9dcb224f7531.png

然後我們啟動服務

服務狀態檢視命令:netstat -ntlapc 可每隔一秒重新整理一次狀態

tcpdump 工具:

tcpdump -A -XX -i lo

用戶端我們使用 telent 工具連線測試 即可

測試圖如下

bc7132d91046aa3a49d8f7c8338c64b.png

33d593b072b6ad65b75248b76800cc1.png

df67f785bcf2240666ecf525524786b.png

8c614fd5c4408900648de547a85e265.png

連線和關閉圖

8ab46ac1ef078e1c4e4d1a6ba1dd8ec.png

如果是用戶端發起的關閉則狀態則是:

用戶端先傳送一個結束報文 FIN 包,此時處於 FIN_WAIT1 狀態,伺服器確認應答處於 CLOSE_WAIT 狀態

此時用戶端處於 FIN_WAIT2 狀態,當伺服器也發了一次 FIN 結束報文時,伺服器處於 LAST_LOCK 狀態,用戶端確認後處於 TIME_WAIT 狀態,伺服器則是關閉 CLOSED 了

狀態轉移圖

761166dfaad8fcb11d8e8e614613343.png

不管你用的是 PHP 提供的 SOCKET API 還是 SWOOLE 或是 C 寫的測試都一樣的!

以上就是TCP 的連線建立與關閉狀態及資料傳輸通訊過程【含有 PHP socket API 測試實驗程式碼】的詳細內容,更多請關注TW511.COM其它相關文章!