程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> php socket通信演示以及socket操作類,phpsocket

php socket通信演示以及socket操作類,phpsocket

編輯:關於PHP編程

php socket通信演示以及socket操作類,phpsocket


  

  准備做Java的課程設計,一個通訊錄。采用C/S架構。客戶端用java FX和Java,服務器端用php,采用socket通信。

  下面來講一講php的socket通信:

  講之前,得先講一下TCP/IP,UDP。隨著互聯網應用的日益廣泛,相信很多人或多或少都聽說過這些協議,那麼到底它們是什麼呢?

  1、什麼是TCP/IP、UDP?

         TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,是一個工業標准的協議集,它是為廣域網(WANs)設計的。TCP/IP協議族包括運輸層、網絡層、鏈路層。
         UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種。

            下面我們上圖直觀地展示一下它們的關系:

               

   這裡並沒有socket什麼事,那socket到底在哪裡呢?又有什麼用?別急,接下來我們就來介紹一下socket與它們的關系。同樣上圖。

      
    現在明白它們的關系了吧。那socket到底是什麼?又有什麼用?

       2、socket是什麼?有什麼用?

    Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。

       既然socket是一組封裝好的接口,那我們如何去運用它來通信呢?具體是一個什麼流程呢?我們可以詳細一下我們打電話的過程。首先我們的電話肯定是處於監聽狀態的,沒錯吧。如果不是,那肯定也不會接到別人打的電話。當被人打電話過來時,首先是先撥號,號碼是目標,也是唯一的。撥號後電話會開始連接,接通了之後就可以開始交談,聊完了之後要掛斷電話,這樣別人才能再打通這個號碼。 socket也是一樣的,服務器端要先建立socket監聽自己電腦某個端口,當有客戶端創建socket發起連接請求時接受,這樣就可以開始傳遞信息了,傳輸完之後再把socket關閉。當然,服務器端也可以主動向客戶端發起連接請求然後開始通信。這是區別於ajax,是可以雙向通信的。下面看圖:

        

  先從服務器端說起。服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束

 

       3、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_delete() 刪除一個已分配的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() 寫數據到分散/聚合數組

 

 

4、socket通信演示:

//服務器端:
<?php //確保在連接客戶端時不會超時 set_time_limit(0); $ip = '127.0.0.1'; $port = 1935; /* +------------------------------- * @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() 失敗的原因是:".socket_strerror($sock)."\n"; } if(($ret = socket_bind($sock,$ip,$port)) < 0) { echo "socket_bind() 失敗的原因是:".socket_strerror($ret)."\n"; } if(($ret = socket_listen($sock,4)) < 0) { echo "socket_listen() 失敗的原因是:".socket_strerror($ret)."\n"; } $count = 0; do { if (($msgsock = socket_accept($sock)) < 0) { echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n"; break; } else { //發到客戶端 $msg ="測試成功!\n"; socket_write($msgsock, $msg, strlen($msg)); echo "測試成功了啊\n"; $buf = socket_read($msgsock,8192); $talkback = "收到的信息:$buf\n"; echo $talkback; if(++$count >= 5){ break; }; } socket_close($msgsock); } while (true); socket_close($sock); ?>
//客戶端
<?php error_reporting(E_ALL); set_time_limit(0); $ip = "127.0.0.1"; $port = 1935; /* +------------------------------- * @socket連接整個過程 +------------------------------- * @socket_create * @socket_connect * @socket_write * @socket_read * @socket_close +-------------------------------- */ $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket < 0) { echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n"; }else { echo "OK.\n"; } echo "試圖連接 '$ip' 端口 '$port'...\n"; $result = socket_connect($socket, $ip, $port); if ($result < 0) { echo "socket_connect() failed.\nReason: ($result) " . socket_strerror($result) . "\n"; }else { echo "連接OK\n"; } $in = "Ho\r\n"; $in .= "first blood\r\n"; $out = ''; if(!socket_write($socket, $in, strlen($in))) { echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n"; }else { echo "發送到服務器信息成功!\n"; echo "發送的內容為:<font color='red'>$in</font> <br>"; } while($out = socket_read($socket, 8192)) { echo "接收服務器回傳信息成功!\n"; echo "接受的內容為:",$out; } echo "關閉SOCKET...\n"; socket_close($socket); echo "關閉OK\n"; ?>

  注意:1)服務器端要用CLI方式運行,也就是命令行模式運行。不要用CGI方式(浏覽器訪問);找到php.exe所在目錄,然後運行以下代碼,php 服務器文件;

    

               2)運行之後可以另開dos窗口下運行netstat -ano查看端口占用情況。

    

 

 

  5、把socket封裝成類:

//ServerSocket.class.php
//客戶端socket操作類
<?php
   error_reporting(E_ALL);
   set_time_limit(0);
   
   class ServerSocket {
        private $server_host;  //服務器IP
     private $server_port;  //服務器端口
     private $client_host;  //客戶端IP
     private $client_port;  //客戶端端口
     private $create_socket=null;   
     private $accept_socket=null;
     private $get_data="";
     private $send_data="";    
     
     //夠造函數
     public function __construct($host,$port){
         if(!extension_loaded("socket")){
             exit("請先打開socket擴展!");
         }
         if(empty($host)) 
             exit("請輸入目標主機IP!");
         if(empty($port))
             exit("請輸入有效端口號!");
         $this->server_host=$host;
         $this->server_port=$port;
         $this->CreateSocket();
     }
     
     //創建一個socket並將其用來綁定監聽端口
     private function createSocket(){
           if($this->create_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)==false){
                 echo "socket_create() failed. reason:".socket_strerror(socket_last_error())."\n";
           }
           if(socket_bind($this->create_socket,$this->server_host,$this->server_port)==false){
               echo "socket_bind()failed. reason:".socket_strerror(socket_last_error($this->create_socket))."\n";
           }
           if(socket_listen($this->create_socket,5)==false){
               echo "socket_listen()failed. reason:".socket_strerror(socket_last_error($this->create_socket))."\n";
           }        
     }
     
     //向目標主機發起連接
     public function connectClient(){
         if(socket_getpeername($this->create_socket,$this->client_host,$this->client_port)==null){
             echo "socket_getpeername()failed. reason:".socket_strerror(socket_last_error($this->create_socket))."\n";
         }
         if(socket_connect($this->create_socket,$this->client_host,$this->client_port)==false){
             echo "socket_connect()failed. reason:".socket_strerror(socket_last_error($this->create_socket))."\n";
         }
     }
     //接受連接獲取到一個socket資源,想客戶端讀取以及傳輸信息
     public function wr(){
         do{   //循環防止阻塞延遲
             if($this->accept_socket=socket_accept($this->create_socket)==null){
                 echo "socket_accept()failed. reason:".socket_strerror(socket_last_error($this->create_socket))."\n";
                 break;
             }
             
             $this->get_data = socket_read($this->accept_socket, 8192);
             $this->send_data=$this->operateData($this->get_data);
             if (socket_write($this->accept_socket,$this->send_data, strlen($this->send_data))==false) {
                 echo "socket_write() failed reason:" . socket_strerror(socket_last_error($this->accept_socket)) ."\n";
             }
             socket_close($this->accept_socket);
         }while(true);          
     }
     
     //數據處理
     private function operateData(){
         
         return ;
     }
     
     //關閉監聽socket
     private function closeSocket(){
         socket_close($this->createSocket);
     }
     
     //析構函數
     public function  __destruct(){
          $this->closeSocket();
     }
   }
  
   
   
//ClientSocket.class.php
//客戶端socke操作類

class Socket {
    private $host;//連接socket的主機
    private $port;//socket的端口號 
    private $error=array();
    private $socket=null;//socket的連接標識
    private $queryStr="";//發送的數據
    public function __construct($host,$port) {
        if(!extension_loaded("sockets")){
            exit("請打開socket擴展 ");
        }
        if(empty($host)) exit("請輸入目標地址");
        if(empty($port)) exit("請輸入有效的端口號");
        $this->host=$host;
        $this->port=$port;
        $this->CreateSocket();//創建連接        
    }

    //創建socket
    private function CreateSocket(){
        !$this->socket&&$this->socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//創建socket
        $r=@socket_connect($this->socket,$this->host,$this->port);
        if($r){
            return $r;
        }else{
            $this->error[]=socket_last_error($this->socket);
            return false;
        }
    }

    //向socket服務器寫入數據並讀取
    public function wr($contents){
        $this->queryStr="";
        $this->queryStr=$contents;
        !$this->socket&&$this->CreateSocket();
        $contents=$this->fliterSendData($contents);
        $result=socket_write($this->socket,$contents,strlen($contents));
        if(!intval($result)){
            $this->error[]=socket_last_error($this->socket);
            return false;
        }
        $response=socket_read($this->socket,12048);
        if(false===$response){
            $this->error[]=socket_last_error($this->socket);
            return false;
        }
        return $response;
    }

    //對發送的數據進行過濾
    private function fliterSendData($contents){
        //對寫入的數據進行處理
        return $contents;
    }

    //所有錯誤信息 
    public function getError(){
        return $this->error;
    }

    //最後一次錯誤信息
    public function getLastError(){
        return $this->error(count($this->error));
    }
    
    //獲取最後一次發送的消息
    public function getLastMsg(){
        return $this->queryStr;
    }

    public function getHost(){
        return $this->host;
    }

    public function getPort(){
        return $this->port;
    }

    //關閉socket連接
    private function close(){
        $this->socket&&socket_close($this->socket);//關閉連接
        $this->socket=null;//連接資源初始化
    }

    public function __destruct(){
        $this->close();
    }
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved