這篇文章將會介紹一下 Socket 編程中相關的 PHP 函數,並簡單實現一個 C/S 的交互
Socket 的官方解釋:
在網絡編程中最經常使用的方案即是Client/Server(客戶機/服務器)模型。在這種方案中客戶應用程序向服務器程序請求服務。一個服務程序一般在一個衆所周知的地址監聽對服務的請求,也就是說,服務進程一 直處於休眠狀態,直到一個客戶向這個服務的地址提出了鏈接請求。在這個時刻,服務程序被"驚醒"而且爲客戶提供服務-對客戶的請求做出適當的反應。爲了方便這種Client/Server模型的網絡編程,90年代初,由Microsoft聯合了其餘幾家公司共同制定了一套WINDOWS下的網絡編程接口,即WindowsSockets規範,它不是一種網絡協議,而是一套開放的、支持多種協議的Windows下的網絡編程接口。如今的Winsock已經基本上實現了與協議無關,你可使用Winsock來調用多種協議的功能,但較常使用的是TCP/IP協議。Socket實際在計算機中提供了一個通訊端口,能夠經過這個端口與任何一個具備Socket接口的計算機通訊。應用程序在網絡上傳輸,接收的信息都經過這個Socket接口來實現php
咱們能夠簡單的把 Socket 理解爲一個能夠連通網絡上不一樣計算機應用程序之間的管道,把一堆數據從管道的 A 端扔進去,則會從管道的 B 端(同時還能夠從C、D、E、F……端冒出來)。linux
注意
:咱們會在不一樣語境下使用不一樣的詞語去修飾 socket,你只須要對它有個概念就行了,由於 socket 自己就沒有真正意義上的實體編程
Socket 通訊依次會進行 Socket 建立、 Socket 綁定、Socket 監聽、Socket 收發、Socket 關閉幾個階段,下面咱們列舉出 PHP 網絡編程中最經常使用也是必不可少的幾個經常使用的函數進行進一步的說明。服務器
TODO : 建立一個新的 socket 資源
函數原型: resource socket_create ( int $domain , int $type , int $protocol )
它包含三個參數,分別以下:網絡
AF
的釋義就 address family
,地址族的意思,咱們經常使用的有 ipv四、ipv6SOCK_STREAM
,基於字節流的SOCKET類型,也是TCP協議使用的類型TODO : 將建立的 socket 資源綁定到具體的 ip 地址和端口
函數原型: bool socket_bind ( resource $socket , string $address [, int $port = 0 ] )
dom
它包含三個參數,分別以下:socket
socket_create
建立的 socket 資源,能夠認爲是 socket 對應的 idTODO : 在具體的地址下監聽 socket 資源的收發操做
函數原型: bool socket_listen ( resource $socket [, int $backlog = 0 ] )
函數
它包含兩個個參數,分別以下:spa
socket_create
建立的socket資源TODO : 監聽以後,接收一個即未來臨的新的鏈接,若是鏈接創建成功,將返回一個新的 socket 句柄(你能夠理解爲子進程,一般父進程用來接收新的鏈接,子進程負責具體的通訊)
函數原型: resource socket_accept ( resource $socket )
命令行
socket_create
建立的socket資源TODO : 將指定的數據發送到 對應的 socket 管道
函數原型: int socket_write ( resource $socket , string $buffer [, int $length ] )
socket_create
建立的socket資源socket
資源中的數據socket
資源中的buffer
的長度,若是長度大於buffer
的容量,則取buffer
的容量TODO : 獲取傳送的數據
函數原型: int socket_read ( resource $socket , int $length )
socket_create
建立的socket資源socket
資源中的buffer
的長度TODO : 關閉 socket 資源
函數原型: void socket_close ( resource $socket )
socket_accept
或者socket_create
產生的資源,不能用於stream
資源的關閉因爲建立一個SOCKET的流程老是 socket、bind、listen,因此PHP提供了一個很是方便的函數一次性建立、綁定端口、監聽端口
函數原型: resource stream_socket_server ( string $local_socket [, int &$errno [, string &$errstr [, int $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN [, resource $context ]]]] )
stream_context_create
函數建立的資源流上下文基於上面的函數咱們能夠很方便的去構建 socket 通訊程序(在這裏我但願讀者能單獨創建一個目錄好比socket
由於後續咱們還會創建不少文件)咱們先編輯一個服務端程序 server.php
,以下:
<?php date_default_timezone_set("Asia/Shanghai"); error_reporting(E_NOTICE ); /* 確保在鏈接客戶端時不會超時 */ set_time_limit(0); $ip = '127.0.0.1'; $port = 8090; /* +------------------------------- * @socket通訊整個過程 +------------------------------- * @socket_create * @socket_bind * @socket_listen * @socket_accept * @socket_read * @socket_write * @socket_close +-------------------------------- */ /*---------------- 如下操做都是手冊上的 -------------------*/ if(($sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) { echo "socket_create() Why failure is:".socket_strerror($sock)."\n"; } if(($ret = socket_bind($sock,$ip,$port)) < 0) { echo "socket_bind() Why failure is:".socket_strerror($ret)."\n"; } if(($ret = socket_listen($sock,4)) < 0) { echo "socket_listen() Why failure is:".socket_strerror($ret)."\n"; } echo "Start time:".date('Y-m-d H:i:s') . PHP_EOL; echo "Listening at ".$ip.':'.$port.PHP_EOL; do { /* 建立新的鏈接 */ if (($msgsock = socket_accept($sock)) < 0) { echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n"; break; } else { # 鏈接成功輸出 Socket id $i = (int)$msgsock; echo "welcome client $i"; # 向客戶端通訊(反饋) $msg ="鏈接成功!\n"; socket_write($msgsock, $msg, strlen($msg)); } socket_close($msgsock); } while (true); socket_close($sock); ?>
再編輯一個客戶端程序client.php
,以下:
<?php set_time_limit(0); $port = 8090; $ip = "127.0.0.1"; /* +------------------------------- * 客戶端 socket 鏈接整個過程 +------------------------------- * @socket_create * @socket_connect * @socket_write * @socket_read * @socket_close +-------------------------------- */ /** * @socket_connect:客戶端發起套接字鏈接 * @param socket resource $socket 建立的$socket資源 * @param address string SOCK_STREAM IP地址|Unix套接字 * @param port int 端口 */ /** * @socket_create:建立並返回一個套接字 * @param domain string AF_INET IPV4 網絡協議 * @param type string SOCK_STREAM 全雙工字節流(可用的套接字類型) * @param protocol string SOL_TCP 具體協議(IPV4下的TCP協議) * @param return 套接字 */ $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket < 0) { echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n"; }else { echo "try to connect '$ip' port: '$port'...\n"; } $result = socket_connect($socket, $ip, $port); #socket_connect的返回值應該是boolean值 if ($result < 0) { echo "socket_connect() failed.\nReason: ($result) " . socket_strerror($result) . "\n"; }else { # 鏈接成功輸出提示信息 echo "connect successfully\n"; # 向服務端發送數據 socket_write($socket, " hello ", 1024); # 獲取服務端數據 $result = socket_read($socket, 1024); echo "服務器回傳數據爲:" . $result; echo "CLOSE SOCKET...\n"; socket_close($socket); echo "CLOSE OK\n"; } ?>
而後咱們打開終端(命令行)進入文件目錄下依次執行:
php server.php php client.php
運行效果以下:
注意
服務器監聽時進程是掛起的不能進行其餘操做,你可能須要另起一個終端執行客戶端程序
本篇文章就是爲你們整理了一下 PHP Socket 編程經常使用的函數並解釋了一下各自的意義,而後寫了一個簡單的 C/S 交互,但願你們對網絡編程有個比較直觀的認識,下篇文章我會簡單講講進程在網絡編程中的做用,這也是爲後面網絡模型的講解打個基礎