php中socket通訊詳解

來源:互聯網
上載者:User
有時候我們的php程式需要和其他系統通訊,比如一個企業的官網提供產品溯源資訊的查詢,在後台網站就需要和企業的溯源系統或ERP系統通訊,此時就需要進行php的網路編程,php提供了一個sockets擴充,官網地址為:

http://nl3.php.net/manual/zh/intro.sockets.php

該擴充讓我們有能力通過php直接操縱通訊端socket,這樣就可以和其他系統通訊了,我們使用socket在OSI網路模型的傳輸層以上工作,直接使用TCP、UDP提供的服務,因此可以使用它作為其他應用程式層協議的用戶端,比如類比HTTP用戶端(瀏覽器),常見的smtp、pop、ftp都可以用它類比,比較好玩的是可以使用它和允許TELNET的伺服器互動,這些協議都是應用程式層協議所以它都可以互動,自訂的系統間通訊就需要自訂協議了。

這裡提供一個樣本,用php開發一個簡單的檔案接收伺服器,另一個php用戶端程式展示如何和這個伺服器程式通訊,代碼如下。

伺服器端程式:

<?php/** * 本程式示範php網路編程:socket通訊 需要php開啟php_sockets擴充 * 這是一個簡易的伺服器程式,接收用戶端發送的檔案,儲存後關閉 * 通訊協議約定為:檔案大小::副檔名::有效資料 * 通訊結束標識符為:“-end-” * 在命令列或瀏覽器中執行均可,推薦命令列 * 作者:雲客【雲遊天下,作客四方】 *//****配置****///要綁定監聽的本機ip地址和連接埠$address = '127.0.0.1';$port = 81;error_reporting(E_ALL);//防止逾時set_time_limit(0);//開啟絕對刷送,禁止緩衝內容ob_implicit_flush();//建立通訊端資源if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";}//綁定通訊端到連接埠if (socket_bind($sock, $address, $port) === false) {    echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";}//開始監聽連接埠,參數5表示可以讓5個串連請求在緩衝中排隊//排隊的連結請求會在前一個串連斷掉後才開始執行,該處緩衝排隊數滿五個後,後面的連結請求將直接忽略,用戶端顯示無法連結//注意這個5並不是指可以並發進行5個連結,而是允許讓5個後續連結進入排隊if (socket_listen($sock, 5) === false) {    echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";}do {    //程式運行到此處進行阻塞,就像暫停執行一樣,一旦有請求進入,該函數停止阻塞,返回連結資源    if (($client_sock = socket_accept($sock)) === false) {        echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";        break;    }    echo "[client connect start]\n";    $data = ""; //接收的資料    $data_size = -1; //接收的資料大小    $received_size = 0; //實際接收的資料    $ext_name = "txt"; //預設副檔名    //開始與用戶端互動    do {        //運行到該處產生阻塞,一旦有內容則停止阻塞狀態,返回內容        if (false === ($buf = socket_read($client_sock, 2048))) {            echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($client_sock)) . "\n";            break 2; //讀取不了就返回失敗,此處的2會讓用戶端斷掉連結後停止本類比伺服器        }        if ($data_size === -1) {//第一次接受資料,解析通訊協議            $arr = explode("::", $buf, 3);            $data_size = (int)$arr[0];            $ext_name = $arr[1];            $data .= $arr[2];            $received_size += strlen($data);            continue;        }        $data .= $buf;        $received_size += strlen($buf);        if ($data_size <= $received_size) {            if ($data_size < $received_size) {                $data = substr($data, 0, $data_size);            }            echo "received:" . $received_size . "/" . "total:" . $data_size;            $talkback = "-end-"; //發送通訊結束標誌            socket_write($client_sock, $talkback, strlen($talkback));            file_put_contents("servertest." . $ext_name, $data);            break 2; //關閉伺服器        }        echo $talkback = "received:" . $received_size . "\n";        socket_write($client_sock, $talkback, strlen($talkback));    } while (true);    socket_close($client_sock);} while (true);socket_close($sock);?>

用戶端程式:

<?php/** * 本程式示範php網路編程:socket通訊 需要php開啟php_sockets擴充 * 這是一個簡易的用戶端程式,向伺服器傳送檔案 * 通訊協議約定為:檔案大小::副檔名::有效資料 * 通訊結束標識符為:“-end-” * 在命令列或瀏覽器中執行均可,推薦命令列,需先開啟伺服器端 * 作者:雲客【雲遊天下,作客四方】 *//****配置****/$file = "yunke.jpg"; //待發送的檔案//伺服器ip和連接埠號碼$address = '127.0.0.1';$port = 81;error_reporting(E_ALL);// 防止逾時 set_time_limit(0);// 開啟絕對刷送,不要緩衝輸出ob_implicit_flush(true);//建立通訊端資源if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";    exit();}//開啟到遠程主機的連結if (socket_connect($sock, $address, $port) === false) {    echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";    exit();}//構造一個很大的待發送資料 大約10MB/*$data = "";for ($i = 1; $i <= 10000000; $i++) {    $data .= "data:" . $i;}$data = $data . $data . $data;*/$data = file_get_contents($file);$data_size = strlen($data);$arr_temp = explode('.', $file);$ext_name = end($arr_temp);$sock_data = $data_size . "::" . $ext_name . "::" . $data;//發送資料給遠程主機while (true) {    $sock_data_size = strlen($sock_data);    $send_size = socket_write($sock, $sock_data, $sock_data_size);    if ($send_size === false) {        echo "send false:" . socket_strerror(socket_last_error($sock)) . "\n";        socket_close($sock);        echo "[client shutdown]\n";        exit();    }    if ($send_size == $sock_data_size) {        break;    }    $sock_data = substr($sock_data, $send_size);}//讀返回資料while (true) {    if (false === ($out = socket_read($sock, 2048))) {        echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";        break 1;    }    echo "server: " . $out . "\n";    if (substr($out, -5) == "-end-") { //約定結束標誌        break;    }}//關閉通訊端資源socket_close($sock);echo "[client shutdown]\nsend data:" . format($data_size);function format($byte = 0){    if ($byte > 1024 * 1024) {        return ceil($byte / (1024 * 1024)) . "MB";    } elseif ($byte > 1024) {        return ceil($byte / 1024) . "KB";    } else {        return $byte . " Byte";    }}


該樣本展示通過一個TCP短連結的方式向伺服器傳送一個檔案,在實際的項目中通訊模組不會這麼簡單,需要考慮更多的問題

比如:

是否需要長串連的方式(一個tcp連結裡面多次來回傳送資料)、資料校正防止損壞、不同系統間的大小端位元組序問題、自訂通訊協議、粘包問題、逾時處理、並發訪問、流量控制、TCP封包解包等等

如果想深入瞭解php網路編程以上提到的這些都需要系統學習,推薦看一看workerman的實現

它是一個php寫的socket伺服器架構,協助解決socket通訊問題,使用它可以建立一個自訂伺服器等等
workerman官網地址為:http://www.workerman.net/

以下再提供兩個查看伺服器HTTP頭和瀏覽器頭的樣本程式:

以下樣本查看伺服器返回的頭資訊,修改需要查看的伺服器位址,然後在瀏覽器中訪問該指令碼即可:

<?phperror_reporting(E_ALL);// 防止逾時 set_time_limit(0);// 開啟絕對刷送,不要緩衝輸出ob_implicit_flush(true);$address = 'www.qq.com'; //要查看的伺服器$port=80;//建立通訊端資源if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";    exit();}//開啟到遠程主機的連結if (socket_connect($sock, gethostbyname($address), $port) === false) {    echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";    exit();}//構造http頭$msg = "GET / HTTP/1.1 \r\n";$msg .= "Host: {$address}\r\n";$msg .= "Connection: Close\r\n\r\n";  //指示伺服器發回完畢就斷開,不必等等其他資源的連結//如果沒有該行會,伺服器會一直等待我方繼續發送資料,直到逾時關閉//而我方不會再發送,這個會讓下面的socket_read函數互為等待,等很久//發送給遠程主機socket_write($sock, $msg, strlen($msg));$str="";while ($out = @socket_read($sock, 2048*4)) {    $str.=$out;}$str=explode("\r\n\r\n", $str);$str=$str[0];if($str){    echo "<pre>\r\n".$str."\r\n</pre>";}else{    echo "nothing";}//關閉通訊端資源socket_close($sock);

以下是查看瀏覽器頭的樣本,可以方便的查看瀏覽器發送的會話資訊
首先確定關閉了80連接埠,然後修改原生host檔案,將想訪問的網址定向到本機127.0.0.1地址,使用php命令列模式啟動此指令碼,然後使用瀏覽器訪問已設定定向的網址即可,該程式會一直開啟,如需關閉請在控制台使用ctrl+c按鍵組合,程式如下:

<?phperror_reporting(E_ALL);//防止逾時set_time_limit(0);//開啟絕對刷送,禁止緩衝內容ob_implicit_flush();$address = '127.0.0.1';$port = 80;//建立通訊端資源if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {    echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";}//綁定通訊端到連接埠if (socket_bind($sock, $address, $port) === false) {    echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";}//開始監聽連接埠,參數5表示可以讓5個串連請求在緩衝中排隊//排隊的連結請求會在前一個串連斷掉後才開始執行,該處緩衝排隊數滿五個後,後面的連結請求將顯示無法連結//注意這個5並不是指可以並發進行5個連結,而是允許讓5個後續連結進入排隊if (socket_listen($sock, 5) === false) {    echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";}do {    //程式運行到此處進行阻塞,就像暫停執行一樣,一旦有請求進入,該函數停止阻塞,返回連結資源    //可以使用socket_set_nonblock函數設定非阻塞模式    if (($msgsock = socket_accept($sock)) === false) {        echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";        break;    }        //連結成功後在控制台顯示提示    echo "[client start ".date("Y-m-d H:i:s")."]\n\n";        do {        //運行到該處產生阻塞,一旦有內容則停止阻塞狀態,返回內容        if (false === ($buf = socket_read($msgsock, 2048*6))) {            echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n";            break 2; //讀取不了就返回失敗,此處的2會讓用戶端斷掉連結後停止本類比伺服器        }        $talkback ="HTTP/1.1 200 OK\r\n\r\n";        $talkback .= date("Y-m-d H:i:s")."\nBrowser HTTP Headers:\n\n".$buf."\n";        //向用戶端顯示該內容        socket_write($msgsock, $talkback, strlen($talkback));        //向伺服器控制台顯示該內容        echo "$buf\n";        break ; //中斷本次與瀏覽器的連結    } while (true);    socket_close($msgsock);} while (true);socket_close($sock);?>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.