回覆列表
  • 1 # 使用者9414740708409

    PHP使用Berkley的socket庫來建立它的連線。你可以知道socket只不過是一個數據結構。你使用這個socket資料結構去開始一個客戶端和伺服器之間的會話。這個伺服器是一直在監聽準備產生一個新的會話。當一個客戶端連線伺服器,它就開啟伺服器正在進行監聽的一個埠進行會話。這時,伺服器端接受客戶端的連線請求,那麼就進行一次迴圈。現在這個客戶端就能夠傳送資訊到伺服器,伺服器也能傳送資訊給客戶端。

    產生一個Socket,你需要三個變數:一個協議、一個socket型別和一個公共協議型別。產生一個socket有三種協議供選擇,繼續看下面的內容來獲取詳細的協議內容。

    定義一個公共的協議型別是進行連線一個必不可少的元素。下面的表我們看看有那些公共的協議型別。

    表一:協議

    名字/常量描述

    AF_INET這是大多數用來產生socket的協議,使用TCP或UDP來傳輸,用在IPv4的地址

    AF_INET6與上面類似,不過是來用在IPv6的地址

    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傳輸控制協議,這是一個使用最多的可靠的公共協議,它能保證資料包能夠到達接受者那兒,如果在傳輸過程中發生錯誤,那麼它將重新發送出錯資料包。

    現在你知道了產生一個socket的三個元素,那麼我們就在php中使用socket_create()函式來產生一個socket。這個socket_create()函式需要三個引數:一個協議、一個socket型別、一個公共協議。socket_create()函式執行成功返回一個包含socket的資源型別,如果沒有成功則返回false。

    Resourecesocket_create(intprotocol,intsocketType,intcommonProtocol);

    現在你產生一個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_listen($socket);

    //Moresocketfunctionalitytocome

    ?>

    上面這個例子產生一個你自己的伺服器端。例子第一行,

    $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()把socket繫結在一個IP地址和埠上

    socket_clear_error()清除socket的錯誤或者最後的錯誤程式碼

    socket_close()關閉一個socket資源

    socket_connect()開始一個socket連線

    socket_create_listen()在指定埠開啟一個socket監聽

    socket_create_pair()產生一對沒有區別的socket到一個數組裡

    socket_create()產生一個socket,相當於產生一個socket的資料結構

    socket_get_option()獲取socket選項

    socket_getpeername()獲取遠端類似主機的ip地址

    socket_getsockname()獲取本地socket的ip地址

    socket_iovec_add()新增一個新的向量到一個分散/聚合的陣列

    socket_iovec_alloc()這個函式建立一個能夠傳送接收讀寫的iovec資料結構

    socket_iovec_fetch()返回指定的iovec資源的資料

    socket_iovec_free()釋放一個iovec資源

    socket_iovec_set()設定iovec的資料新值

    socket_last_error()獲取當前socket的最後錯誤程式碼

    socket_listen()監聽由指定socket的所有連線

    socket_read()讀取指定長度的資料

    socket_readv()讀取從分散/聚合陣列過來的資料

    socket_recv()從socket裡結束資料到快取

    socket_recvfrom()接受資料從指定的socket,如果沒有指定則預設當前socket

    socket_recvmsg()從iovec裡接受訊息

    socket_select()多路選擇

    socket_send()這個函式傳送資料到已連線的socket

    socket_sendmsg()傳送訊息到socket

    socket_sendto()傳送訊息到指定地址的socket

    socket_set_block()在socket裡設定為塊模式

    socket_set_nonblock()socket裡設定為非塊模式

    socket_set_option()設定socket選項

    socket_shutdown()這個函式允許你關閉讀、寫、或者指定的socket

    socket_strerror()返回指定錯誤號的詳細錯誤

    socket_write()寫資料到socket快取

    socket_writev()寫資料到分散/聚合陣列

    (注:函式介紹刪減了部分原文內容,函式詳細使用建議參考英文原文,或者參考PHP手冊)

    以上所有的函式都是PHP中關於socket的,使用這些函式,你必須把你的socket開啟,如果你沒有開啟,請編輯你的php.ini檔案,去掉下面這行前面的註釋:

    extension=php_sockets.dll

    如果你無法去掉註釋,那麼請使用下面的程式碼來載入擴充套件庫:

    if(!extension_loaded(‘sockets’))

    {

    if(strtoupper(substr(PHP_OS,3))==“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,"localhost",1337);

    socket_listen($socket);

    //Acceptanyincomingconnectionstotheserver

    $connection=socket_accept($socket);

    if($connection)

    {

    socket_write($connection,"Youhaveconnectedtothesocket.../n/r");

    }

    ?>

    你應該使用你的命令提示符來執行這個例子。理由是因為這裡將產生一個伺服器,而不是一個Web頁面。如果你嘗試使用Web瀏覽器來執行這個指令碼,那麼很有可能它會超過30秒的限時。你可以使用下面的程式碼來設定一個無限的執行時間,但是還是建議使用命令提示符來執行。

    set_time_limit(0);

    在你的命令提示符中對這個指令碼進行簡單測試:

    Php.exeexample01_server.php

    如果你沒有在系統的環境變數中設定php直譯器的路徑,那麼你將需要給php.exe指定詳細的路徑。當你執行這個伺服器端的時候,你能夠透過遠端登陸(telnet)的方式連線到埠1337來測試這個伺服器。如下圖:

    上面的伺服器端有三個問題:1.它不能接受多個連線。2.它只完成唯一的一個命令。3.你不能透過Web瀏覽器連線這個伺服器。

    這個第一個問題比較容易解決,你可以使用一個應用程式去每次都連線到伺服器。但是後面的問題是你需要使用一個Web頁面去連線這個伺服器,這個比較困難。你可以讓你的伺服器接受連線,然後些資料到客戶端(如果它一定要寫的話),關閉連線並且等待下一個連線。

    在上一個程式碼的基礎上再改進,產生下面的程式碼來做你的新伺服器端:

    //Setupoursocket

    $commonProtocol=getprotobyname("tcp");

    $socket=socket_create(AF_INET,SOCK_STREAM,$commonProtocol);

    socket_bind($socket,"localhost",1337);

    socket_listen($socket);

    //Initializethebuffer

    $buffer="NODATA";

    while(true)

    {

    //Acceptanyconnectionscominginonthissocket

    $connection=socket_accept($socket);

    printf("Socketconnected/r/n");

    //Checktoseeifthereisanythinginthebuffer

    if($buffer!="")

    {

    printf("Somethingisinthebuffer...sendingdata.../r/n");

    socket_write($connection,$buffer."/r/n");

    printf("Wrotetosocket/r/n");

    }

    else

    {

    printf("NoDatainthebuffer/r/n");

    }

    //Gettheinput

    while($data=socket_read($connection,1024,PHP_NORMAL_READ))

    {

    $buffer=$data;

    socket_write($connection,"InformationReceived/r/n");

    printf("Buffer:".$buffer."/r/n");

    }

    socket_close($connection);

    printf("Closedthesocket/r/n/r/n");

    }

    ?>

    這個伺服器端要做什麼呢?它初始化一個socket並且開啟一個快取收發資料。它等待連線,一旦產生一個連線,它將列印“Socketconnected”在伺服器端的螢幕上。這個伺服器檢查緩衝區,如果緩衝區裡有資料,它將把資料傳送到連線過來的計算機。然後它傳送這個資料的接受資訊,一旦它接受了資訊,就把資訊儲存到資料裡,並且讓連線的計算機知道這些資訊,最後關閉連線。當連線關閉後,伺服器又開始處理下一次連線。(翻譯的爛,附上原文)

    Thisiswhattheserverdoes.Itinitializesthesocketandthebufferthatyouusetoreceive

    andsenddata.Thenitwaitsforaconnection.Onceaconnectioniscreateditprints

    “Socketconnected”tothescreentheserverisrunningon.Theserverthencheckstoseeif

    thereisanythinginthebuffer;ifthereis,itsendsthedatatotheconnectedcomputer.

    Afteritsendsthedataitwaitstoreceiveinformation.Onceitreceivesinformationitstores

    itinthedata,letstheconnectedcomputerknowthatithasreceivedtheinformation,and

    thenclosestheconnection.Aftertheconnectionisclosed,theserverstartsthewhole

    processagain.

    ◆ 產生一個客戶端

    處理第二個問題是很容易的。你需要產生一個php頁連線一個socket,傳送一些資料進它的快取並處理它。然後你又個處理後的資料在還頓,你能夠傳送你的資料到伺服器。在另外一臺客戶端連線,它將處理那些資料。

    Tosolvethesecondproblemisveryeasy.YouneedtocreateaPHPpagethatconnectsto

    asocket,receiveanydatathatisinthebuffer,andprocessit.Afteryouhaveprocessedthe

    datainthebufferyoucansendyourdatatotheserver.Whenanotherclientconnects,it

    willprocessthedatayousentandtheclientwillsendmoredatabacktotheserver.

    下面的例子示範了使用socket:

    //Createthesocketandconnect

    $socket=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);

    $connection=socket_connect($socket,’localhost’,1337);

    while($buffer=socket_read($socket,1024,PHP_NORMAL_READ))

    {

    if($buffer==“NODATA”)

    {

    echo(“

    NODATA

    ”);

    break;

    }

    else

    {

    //Dosomethingwiththedatainthebuffer

    echo(“

    BufferData:“.$buffer.“

    ”);

    }

    }

    echo(“

    WritingtoSocket

    ”);

    //Writesometestdatatooursocket

    if(!socket_write($socket,“SOMEDATA/r/n”))

    {

    echo(“

    Writefailed

    ”);

    }

    //Readanyresponsefromthesocket

    while($buffer=socket_read($socket,1024,PHP_NORMAL_READ))

    {

    echo(“

    Datasentwas:SOMEDATA

    Responsewas:”.$buffer.“

    ”);

    }

    echo(“

    DoneReadingfromSocket

    ”);

    ?>

    這個例子的程式碼演示了客戶端連線到伺服器。客戶端讀取資料。如果這是第一時間到達這個迴圈的首次連線,這個伺服器將傳送“NODATA”返回給客戶端。如果情況發生了,這個客戶端在連線之上。客戶端傳送它的資料到伺服器,資料傳送給伺服器,客戶端等待響應。一旦接受到響應,那麼它將把響應寫到螢幕上。

  • 中秋節和大豐收的關聯?
  • 宇宙之大,宇宙存在的意義是什麼?