PHP+Socket系列之實現使用者端與伺服器端資料傳輸

2023-02-02 14:00:27

本篇文章給大家帶來了關於php+socket的相關知識,其中主要介紹了什麼是socket?php+socket如何實現使用者端與伺服器端資料傳輸?感興趣的朋友下面一起來看一下,希望對大家有幫助。

socket介紹

實現網路程序之間的通訊,幾乎所有應用程式都是採用 socket,socket 是應用層與 TCP/IP 協定族通訊的中間抽象層,它是一組介面。在設計模式中,socket 其實是一個門面模式,它把複雜的 TCP/IP 協定族隱藏在 socket 介面後面,對使用者來說,一組簡單的介面就是全部,讓 socket 去組織資料,以符合指定的協定

7617f3b78753cdf0045f85ac8eabdbf.jpg

socket 的英文原意是 「孔」或「插座」,通常也被稱作「通訊端」,用於描述 IP 地址和埠,是一個通訊鏈的控制程式碼,可以用來實現不同虛擬機器器或不同計算機之間的通訊。

socket 連結的三個過程

  • 伺服器端監聽:IP+埠號

  • 使用者端請求:發出向伺服器端的 IP 以及埠的連線請求

  • 連結確認:伺服器端通訊端監聽到或者說接收到使用者端通訊端連線請求,他就會建立一個新的程序,把伺服器端的通訊端描述發給使用者端,以響應使用者端的請求,一旦使用者端確認了此描述,連線就建立好了。兒伺服器端的通訊端繼續處於監聽狀態,繼續接受其他使用者端通訊端的連線請求。

089f4c71a9dec261bb76eb0e1202e85.jpg

php實現socket

如果需要在 php 中使用 socket,則需要在編譯 php 是新增 --enable-sockets 設定項來啟用,可使用 php -m|grep sockets 命令檢查啟用情況,具體編譯過程可參考

快速體驗

伺服器端與使用者端簡略程式碼如下,執行後伺服器端會阻塞等待使用者端連線,使用者端會在控制檯要求輸入內容,輸入後資訊會在伺服器端列印,同時使用者端顯示轉為大寫的內容,此範例伺服器端與使用者端執行在一臺伺服器:

伺服器端監聽

<?php

// 建立通訊端
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

// 設定 ip 被釋放後立即可使用
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, true);

// 繫結ip與埠
socket_bind($socket, 0, 8888);

// 開始監聽
socket_listen($socket);

while (true) {
    // 接收內容
    $conn_sock = socket_accept($socket);
    socket_getpeername($conn_sock, $ip, $port);
    // echo '請求ip: ' . $ip . PHP_EOL . '埠: ' . $port;

    while (true) {
        // 獲取訊息內容
        $msg = socket_read($conn_sock, 10240);
        // TODO 處理業務邏輯

        // 將資訊轉為大寫並原樣返回使用者端
        socket_write($conn_sock, strtoupper($msg));

        echo $msg;
    }
}
登入後複製

使用者端連線

<?php

// 建立通訊端
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

// 連線伺服器端
socket_connect($socket, '127.0.0.1', 8888);

while (true) {
    // 讓控制檯輸入內容
    fwrite(STDOUT, '請輸入內容:');
    $in = fgets(STDIN);

    // 向伺服器端傳送內容
    socket_write($socket, $in);

    // 讀取伺服器端傳送的訊息
    $msg = socket_read($socket, 10240);
    echo $msg;
}
登入後複製

語法解釋

socket_create

socket_create(int $domain,int $type, int $protocol): resource|false
登入後複製

建立並返回一個通訊端資源,通常也稱作一個通訊節點。一個典型的 socket 由至少 2 個通訊端組成,其中一個執行在使用者端,一個執行在伺服器端。

引數:

  • domain 指定當前通訊端使用什麼協定,可用協定如下:

    Domain描述
    AF_INETIPv4 網路協定,TCP 與 UDP 都可使用此協定
    AF_INET6IPv6 網路協定,TCP 與 UDP 都可使用此協定
    AF_UNIX本地通訊協定,具有高效能與低成本的 IPC
  • type 使用者指定當前通訊端使用的型別

    type描述
    SOCK_STREAM可順序化的、可靠的、全雙工的、基於連結的位元組流,支援資料傳送流量控制機制。TCP 協定基於這種流式通訊端。
    SOCK_DGRAM資料包文的支援(無連線、不可靠、固定最大長度)UDP 協定基於這種報文通訊端
    SOCK_SEQPACKET可順序化的、可靠的、全雙工的、面向連線的、固定最大長度的資料通訊,資料端通過接收每一個資料段來讀取整個封包
    SOCK_RAW讀取原始的網路協定,這種特殊的通訊端可用於手工構建任意型別的協定,一般使用這個通訊端來實現 ICMP 請求
    SOCK_RDM可靠的資料層,但不保證到達順序,一般的作業系統都未實現此功能
  • protocol 設定指定 domain 通訊端下的具體協定,如果所需協定是 TCP 或者 UDP,可以直接使用常數 SOL_TCPSOL_UDP,這個引數的具體值可通過 getprotobyname() 函數獲取

返回值

socket_create() 正確時返回一個通訊端資源,失敗時返回 false。可以呼叫 socket_last_error() 獲取錯誤碼,錯誤碼可以通過 socket_strerror(int $err_no) 轉換為文字的錯誤說明。

socket_bind

socket_bind(resource $socket, string $address [, int $port]): bool
登入後複製

繫結一個地址與埠到通訊端

引數:

  • socket 使用 socket_create() 建立的通訊端資源

  • address

    如果通訊端是 AF_INET 族,那麼 address 必須是一個四點法的 IP 地址,例如 127.0.0.10.0.0.0

    如果通訊端是 AF_UNIX 族,那麼 address 是 Unix 通訊端一部分(例如 /tmp/my.sock

  • port (可選)

    該引數僅用於使用 AF_INET 族時,指定當前通訊端監聽的埠號

返回值:

繫結成功返回 true,失敗時則返回 false,同 socket_create ,在繫結失敗時可以呼叫 socket_last_error() 獲取錯誤碼,錯誤碼可以通過 socket_strerror(int $err_no) 轉換為文字的錯誤說明。

socket_listen

socket_listen(resource $socket [, int $backlog]): bool
登入後複製

在使用 socket_create() 建立通訊端並使用 socket_bind() 將其繫結到名稱之後,可能會告訴它偵聽通訊端上的傳入連線。該函數僅適用於 SOCK_STREAMSOCK_SEQPACKET 型別的通訊端。

引數:

  • socket 使用 socket_create() 建立的通訊端資源
  • backlog 最大數量的積壓傳入連線將排隊等待處理,如果連線請求到達時佇列已滿,則使用者端可能會收到指示為 ECONNREFUSED 的錯誤。或者,如果底層協定支援重傳,則可能會忽略該請求,以便重試可能會成功。

返回值:

繫結成功返回 true,失敗時則返回 false,可以呼叫 socket_last_error() 獲取錯誤碼,錯誤碼可以通過 socket_strerror(int $err_no) 轉換為文字的錯誤說明。

socket_accept

socket_accept(resource $socket): resource|false
登入後複製

當有新的使用者端連線時,返回一個新的 socket 資源以用於與使用者端通訊,如有多個連線排隊,則返回第一個連線,相反如果沒有待處理的連線,該函數會預設阻塞當前程序,直至新的使用者端連線、斷開

引數:

  • socket 使用 socket_create() 建立的通訊端資源

返回值:

成功時返回一個新的通訊端資源,錯誤時返回 false,可以呼叫 socket_last_error() 獲取錯誤碼,錯誤碼可以通過 socket_strerror(int $err_no) 轉換為文字的錯誤說明。

socket_connect

socket_connect(resource $socket, string $address [, int $port = null]): bool
登入後複製

使用通訊端範例發起到 address 的連線

引數:

  • socket 該引數必須是由 socket_create() 建立的 socket 範例

  • address

    如果通訊端是 AF_INET 族,那麼 address 必須是一個四點法的 IP 地址,例如 127.0.0.1 如果支援 IPv6 並且通訊端是 AF_INET6,那麼 address 也可以是一個有效的 IPv6 地址(例如 ::1

    如果通訊端是 AF_UNIX 族,那麼 address 是 Unix 通訊端一部分(例如 /tmp/my.sock

返回值:

成功時返回 true, 或者在失敗時返回 false

socket_write

socket_write(resource $socket, string $data [, int $length = null]): int|false
登入後複製

傳輸資料至指定通訊端

引數:

  • socket 使用 socket_create()socket_accept() 建立的通訊端資源

  • data 要傳送的內容

  • length (可選)

    可以指定傳送通訊端的替代位元組長度。如果這個長度大於實際傳送內容的長度,它將被靜默地截斷為實際傳送內容的長度。

返回值:

成功時返回成功傳送的位元組數,或者在失敗時返回 false,可以呼叫 socket_last_error()socket_strerror(int $err_no) 獲取具體錯誤資訊

socket_read

socket_read(resource $socket, int $length, int $mode = PHP_BINARY_READ): string|false
登入後複製

從通訊端資源內讀取資料

引數:

  • socket 使用 socket_create()socket_accept() 建立的通訊端資源(伺服器端為 socket_accept() 使用者端為 socket_create()

  • length 指定最大能夠讀取的位元組數。否則您可以使用 \r\n\0 結束讀取(根據 mode 引數設定)

  • mode (可選)

    PHP_BINARY_READ (預設)- 使用系統的 recv() 函數。二進位制安全地讀取資料。

    PHP_NORMAL_READ - 讀取到 \n\r 時停止。

返回值:

socket_read() 返回一個字串,表示接收到的資料。如果發生了錯誤(包括遠端主機關閉了連線),則返回 false,可以呼叫 socket_last_error()socket_strerror(int $err_no) 獲取具體錯誤資訊

socket_close

socket_close(resource $socket): void
登入後複製

關閉並銷燬一個通訊端資源

引數:

  • socket 使用 socket_create()socket_accept() 建立的通訊端資源

返回值:

推薦學習:《》

以上就是PHP+Socket系列之實現使用者端與伺服器端資料傳輸的詳細內容,更多請關注TW511.COM其它相關文章!