◆ Socket 基礎
php使用Berkley的socket函式庫來建立它的連結。 socket只不過是一個資料結構。你使用這個socket資料結構去開始一個客戶端和伺服器之間的會話。這個伺服器是一直在監聽準備產生一個新的會話。當一個客戶端連接伺服器,它就打開伺服器正在進行監聽的一個連接埠進行會話。這時,伺服器端接受客戶端的連線請求,那麼就進行一次循環。現在這個客戶端就能夠傳送訊息到伺服器,伺服器也能傳送訊息給客戶端。
產生一個Socket,你需要三個變數:一個協定、一個socket類型、一個公共協定類型。產生一個socket有三種協議供選擇,繼續看下面的內容來獲取詳細的協議內容。
定義一個公共的協議類型是進行連接一個必不可少的元素。下面的表我們看看有那些公共的協議類型。
表一:協議
名字/常數 描述
AF_INET 這是大多數用來產生socket的協議,使用TCP或UDP來傳輸,用在ipv4的地址
AF_INET6 AF_UNIX 本地協議,使用在Unix和linux系統上,它很少使用,一般都是當客戶端和伺服器在同一台機器上的時候使用
表二:Socket類型
名字/常量 描述
SOCK_STREAM 這個協議是按照順序的、可靠的、資料完整的基於位元組流的連接。這是一個使用最多的socket類型,這個socket是使用TCP來進行傳輸。
SOCK_DGRAM 這個協定是無連線的、固定長度的傳輸呼叫。該協定是不可靠的,使用UDP來進行它的連接。
SOCK_SEQPACKET 這個協定是雙線路的、可靠的連接,發送固定長度的資料包進行傳輸。必須把這個包完整的接受才能進行讀取。
SOCK_RAW 這個socket類型提供單一的網路訪問,這個socket類型使用ICMP公共協定。 (ping、traceroute使用該協定)
SOCK_RDM 這個類型是很少使用的,在大部分的作業系統上沒有實現,它是提供給資料鏈結層使用,不保證資料包順序
表三:公共協定
名字/常數 描述
ICMP 互聯網控制訊息協議,主要使用在網關和主機上,用來檢查網路狀況和報告錯誤訊息
UDP 用戶資料封包協議,它是一個無連接,不可靠的傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議
TCP 傳輸協議控制協議,這是一個使用最多的可靠的公共協議,它能保證資料包能夠到達接受者那兒,如果在傳輸過程中發生錯誤,那麼它將重新發送出錯資料包。
現在你知道產生一個socket的三個元素,那麼我們就在php中使用socket_create()函數來產生一個socket。這個socket_create()函數需要三個參數:一個協定、一個socket類型、一個公共協定。 socket_create()函數執行成功傳回一個包含socket的資源類型,如果沒有成功則傳回false。
Resourece socket_create(int PRotocol, int socketType, int commonProtocol);
現在你產生一個socket,然後呢? php提供了幾個操縱socket的函數。你能夠綁定socket到一個IP,監聽一個socket的通信,接受一個socket;現在我們來看一個例子,了解函數是如何產生、接受和監聽一個socket。
$commonProtocol = getprotobyname(“tcp”);//使用公共協定名字來取得一個協定類型
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);///產生一個產生資源的實例
socket_bind($socket, 'localhost', 1337);//綁定socket到本地電腦
socket_listen($socket);//監聽所有進來的socket連接
// More socket functionality to come🎜// More socket functionality to come🎜// More socket functionality to come🎜上面這個例子產生一個你自己的伺服器端。範例第一行,🎜$commonProtocol = getprotobyname(“tcp”);🎜使用公共協定名字來取得一個協定類型。這裡使用的是TCP公共協議,如果你想使用UDP或ICMP協議,那麼你應該把getprotobyname()函數的參數改為「udp」或「icmp」。還有一個可選的方法是不使用getprotobyname()函數而是指定SOL_TCP或SOL_UDP在socket_create()函數中。 🎜$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);🎜範例的第二行是產生一個socket並且傳回一個socket資源的實例。在你有了一個socket資源的實例以後,你就必須把socket綁定到一個IP位址和某一個連接埠上。 🎜socket_bind($socket, ‘localhost’, 1337);🎜在這裡你綁定socket到本地電腦(127.0.0.1)和綁定socket到你的1337埠。然後你就需要監聽所有進來的socket連線。 🎜socket_listen($socket);🎜在第四行以後,你就需要了解所有的socket函數和他們的使用。 🎜表四:Socket函數🎜函數名稱 描述🎜socket_accept() 接受一個Socket連線
socket_bind() 在一個IP位址與連接埠上
socket_clear_error() ect() 開始一個socket連線
socket_create_listen() 在指定連接埠開啟一個socket監聽
socket_create_pair() 產生一對沒有差異的socket到一個陣列裡
socket_create()選項
socket_getpeername() 取得遠端類似主機的ip位址
socket_getsockname() 取得遠端類似主機的ip位址
socket_getsockname() 取得本機socket的ip位址
socket_iovec_add() 新增一個使用建立一個分散/聚合的數位向量到一個分散/聚合的陣列的iovec資料結構
socket_iovec_delete() 刪除一個已分配的iovec
socket_iovec_fetch() 傳回指定的iovec資源的資料
socket_iovec_free() 值
socket_last_error() 取得目前socket的最後錯誤碼
socket_listen() 監聽所有指定socket的連線
socket_read() 讀取指定長度的資料
socket_readv() 讀取指定長度的資料
socket_readv()
socket_recvfrom() 接受資料從指定的socket,如果沒有指定則預設目前socket
socket_recvmsg() 從iovec裡接受訊息
socket_select() 從iovec裡接受訊息
socket_select()
socket_sendmsg( ) 傳送訊息至socket
socket_sendto() 傳送訊息至指定位址的socket
socket_set_block() 在socket裡設定為「區塊模式」.設定socket選項
socket_shutdown() 這個函數允許你關閉讀取、寫入、或指定的socket
socket_strerror() 傳回指定錯誤號碼的詳細錯誤
socket_write() 寫資料到socket快取
socket_writev() 寫資料到socket快取
socket_writev() PHP中關於socket的,使用這些函數,你必須把你的socket打開,如果你沒有打開,請編輯你的php.ini文件,去掉下面這行前面的註釋:
extension=php_sockets.dll
如果你無法去掉註釋,那麼請使用下面的程式碼來載入擴充函式庫:
if(!extension_loaded('sockets')) {
if(strtoupper(substr(PHP_OS, 3)) == “WIN”) {
WIN dl('php_sockets.dll');
}else{
dl('sockets.so');
}
}
?>
如果你不知道你的socket是否打開,那麼你可以使用phpinfo()函數來確定socket是否打開。你透過查看phpinfo資訊來了解socket是否打開。
查看phpinfo()關於socket的資訊
◆ 產生一個伺服器
現在我們把第一個範例做完善。你需要監聽一個指定的socket並且處理使用者的連線。
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'locala,$socket, 'wocken listsocket, 133997]; // Accept any incoming connections to the server
$connection = socket_accept($socket);
if($connection){
socket_write($connection, "You have connected to the socket...nr"); >
你應該使用你的命令提示字元來執行這個範例。理由是因為這裡將產生一個伺服器,而不是Web頁面。如果你嘗試使用網頁瀏覽器來執行這個腳本,那麼很有可能它會超過30秒的限時。你可以使用下面的程式碼來設定一個無限的運行時間,但還是建議使用命令提示字元來運行。
set_time_limit(0);
在你的命令提示字元中對這個腳本進行簡單測試:
Php.exe example01_server.php
如果你沒有在系統的環境變數中設定php解釋器的路徑,那麼你將需要給php.exe指定詳細的路徑。當你運行這個伺服器端的時候,你能夠透過遠端登陸(telnet)的方式連接到連接埠1337來測試這個伺服器。
上面的伺服器端有三個問題:1. 它不能接受多個連線。 2. 它只完成唯一的一個指令。 3. 你不能透過網頁瀏覽器連接這個伺服器。
這個第一個問題比較容易解決,你可以使用一個應用程式去每次都連接到伺服器。但是後面的問題是你需要使用一個Web頁面去連接這個伺服器,這個比較困難。你可以讓你的伺服器接受連接,然後些資料到客戶端(如果它一定要寫的話),關閉連接並且等待下一個連接。
在上一個程式碼的基礎上再改進,產生下面的程式碼來做你的新伺服器端:
// Set up our socket
$commonProtocol = getprotobyname("tcp");
$socket = socket_create (AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337); //socket_bind() 將IP位址和連接埠綁定在一個IP位址和連接埠上
socket_en(list) /$ /$3/2/3] le buffer
$buffer = "NO DATA";
while(true) {
// Accept any connections coming in on this socket
$connection = socket_accept($socket);//socket_accept() Socket connectedrn");
// Check to see if there is anything in the buffer
if($buffer != ""){
printf("Something is in the buffer...sending data...rn");
socket_write($connection, $buffer . "rn"); //socket_write() 寫入資料到socket快取
printf("Wrote to socketrn");
}
// Get the input
while($data = socket_read($connection, 1024, PHP_NORMAL_READ))//socket_read() 讀取指定長度的資料
{f< "Information Receivedrn");
printf("Buffer: " . $buffer . "rn");
}
socket_close($connection); //socket_close() 關閉一個socket資源
printf"Closedrnedrned);
}
?>
這個伺服器端要做什麼呢?它初始化一個socket並且打開一個快取收發資料。它等待連接,一旦產生一個連接,它將列印“Socket connected”在伺服器端的螢幕上。這個伺服器檢查緩衝區,如果緩衝區裡有數據,它將把數據傳送到連接過來的電腦。然後它發送這個數據的接受信息,一旦它接受了信息,就把信息保存到數據裡,並且讓連接的計算機知道這些信息,最後關閉連接。當連線關閉後,伺服器又開始處理下一次連線。
◆ 產生一個客戶端
處理第二個問題是很容易的。你需要產生一個php頁連接一個socket,發送一些資料進它的快取並處理它。然後你有個處理後的資料在還頓,你能夠發送你的資料到伺服器。在另外一台客戶端連接,它將處理那些資料。
下面的範例示範了使用socket:
// Create the socket and connect
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
,$connection = socket_STRconnection;
while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)) {
if($buffer == “NO DATA”) {
echo(“
NO DATA
”);NO DATA
”);Buffer Data: “ . $buffer . “
”);Writing to Socket
”);Write failed
”);Data sent was: SOATA
” buffer . “
Done Reading from Socket
”);