您好,登錄后才能下訂單哦!
如何用PHP編寫Socket程序的方法?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
環境配置
socket 編程需要開啟 php 的 socket 擴展,我用的電腦是 windows,所以這里你只需要打開 php.ini 文件,找到這一行去掉注釋就可以了
extension=sockets
官方文檔
php 的 socket 編程的官方地址為:php socket(https://www.php.net/manual/en/book.sockets.php)
服務端編程
socket 編程遵循一定的編程步驟,這幾個步驟缺一不可,客戶端和服務端編程有所區別,我們首先來看一下服務端。
創建套接字
套接字屬于系統資源,我們首先調用 socket_create 方法(參考官方文檔:https://www.php.net/manual/en/function.socket-create.php),調用如下:
$this->socket_handle = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$this->socket_handle) { //創建失敗拋出異常,socket_last_error獲取最后一次socket操作錯誤碼,socket_strerror打印出對應錯誤碼所對應的可讀性描述 throw new Exception(socket_strerror(socket_last_error($this->socket_handle))); } else { echo "create socket successful\n"; }
第一個參數指定了,當前套接字是采用 ipv4 還是 ipv6,如果是前者的話,那么傳遞 AF_INET,否則 AF_INET6,當然還有一種類型,就是 AF_UNIX,這個暫時不討論,我們一般選擇 AF_INET(ipv6 不是很普及)。
第二個參數,指定了協議的類型,一般選擇 TCP 或者是 UDP,TCP 是可靠的流傳輸(生活當中用的最為廣泛,保證了可靠性和安全性),UDP 則不是,這個參數一般選擇 TCP。
第三個如果你之前選擇了 TCP,那么它就是 SOL_TCP,否則就是 SOL_UDP。
綁定地址和端口號
因為一臺主機可能存在多個 ip 地址,所以你需要指定你的 socket 監聽的是哪一個,常用的值為 127.0.0.1,或者是監聽所有地址 0.0.0.0,那么這里可能有人不明白了,127.0.0.1 和 0.0.0.0 有啥區別呢?127.0.0.1 只是一個回環地址,只能用于本機訪問,說白了就是自己玩自己的,因為這個 ip 不對外部開放,所以有人也就無法訪問這個地址,所以如果你的服務器地址設置為 127.0.0.1,別人想要訪問,只能去屎吧。
0.0.0.0 嚴格來說不算是一個 ip 地址,它的意思是本機的所有 IP 地址,都是我的,哈哈。
明白了上面這個,我們來看這個調用的代碼
if (!socket_bind($this->socket_handle, $this->addr, $this->port)) { throw new Exception(socket_strerror(socket_last_error($this->socket_handle))); } else { echo "bind addr successful\n"; }
是不是很簡單,第一個參數就是 socket_create 返回的結果,第二個參數就是地址了,上面已經說過了,第三個參數是端口號。
監聽套接字
經過上面的這些步驟,我們只是創建了一個套接字并且給它綁定了端口號和地址,但是系統怎么知道它是監聽套接字呢?所以呢,我們的事情還沒有做完,所以我們得告訴它啊,別告訴我你和系統心有靈犀啊!!!
if (!socket_listen($this->socket_handle, $this->back_log)) { throw new Exception(socket_strerror(socket_last_error($this->socket_handle))); } else { echo "socket listen successful\n"; }
第二個參數值得說明一哈,請聽我細細道來,對于 linux 系統中的每一個進程而言,系統都維護著待處理套接字的隊列(先進先出,總得講個先來后到吧),上層程序處理業務邏輯總得需要時間吧,所以讓你你等著你就等著唄。那么這個隊列的大小設置為多大呢?它的值就是這第二個參數,那么我是不是可以設置的很大呢?騷年,你想多了吧?不同的系統這個值有所不同,別說我忽悠你,看下面。
The maximum number passed to the backlog parameter highly depends on the underlying platform. On Linux, it is silently truncated to SOMAXCONN. On win32, if passed SOMAXCONN, the underlying service provider responsible for the socket will set the backlog to a maximum reasonable value. There is no standard provision to find out the actual backlog value on this platform.
你也不必關心這個值精確的數據,沒有什么意義。
萬事俱備,只欠東風
經過上面的一通操作之后,我們可以開始接受來自客戶端的連接了,這個函數就更簡單了
$client_socket_handle = socket_accept($this->socket_handle);
這個函數的返回值也是一個套接字句柄,所以你可以對它進行讀寫操作,在當前的實例程序中,我們做的事情很簡單,簡單到你可以懷疑人生了。
$client_socket_handle = socket_accept($this->socket_handle); if (!$client_socket_handle) { echo "socket_accept call failed\n"; exit(1); } else { while (true) { $bytes_num = socket_recv($client_socket_handle, $buffer, 100, 0); if (!$bytes_num) { echo "socket_recv failed\n"; exit(1); } else { echo "content from client:" . $buffer . "\n"; } } }
讀取套接字
以上面的例子為例,我們使用 socket_recv 讀取來自客戶端的內容,這個函數很簡單,函數原型如下
socket_recv ( resource $socket , string &$buf , int $len , int $flags ) : int
讀取的內容會在第二個參數返回,第二個參數傳遞我們想要讀取的字符數,第四個參數可以直接設置為 0,該函數的返回值為實際讀取的字節數。
客戶端編程
客戶端相對于服務端來說,就很簡單了,流程如下
創建套接字前面已經講過了,不再詳述,客戶端只需要連接服務器即可,函數為 socket_create,我們來看一哈在當前的例子中,我們是如何調用的。
if (!socket_connect($this->socket_handle, $this->server_addr, $this->server_port)) { echo socket_strerror(socket_last_error($this->socket_handle)) . "\n"; exit(1); } else { while (true) { $data = fgets(STDIN); //如果用戶輸入quit,那么退出程序 if (strcmp($data, "quit") == 0) { break; } socket_write($this->socket_handle, $data); } }
該函數只需要指定服務器的地址和端口號即可,參數是不是很簡單
練習實例
在講解基本函數調用的時候,我就把自帶程序的核心部分,復制出來了,如果要完整的程序,這里是地址(php-socket-base-code:https://gitee.com/obamajs/php-socket-base-code),代碼非常簡單,再次提醒,這些代碼完全是用于給大家講解基本的 socket 變成操作,為大家以后的學習打下基礎,那么如何使用這個例子程序呢?
進入到命令行,開啟服務器程序
php TcpServer.php,
打開另外一個命令行界面,
php TcpClient.php,
在客戶端界面,輸入任何文本,再輸入回車,再切換到服務器界面,您將會看到客戶端輸入的內容
在筆者的電腦上操作實例截圖如下:
關于如何用PHP編寫Socket程序的方法問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。