• socket



    转载: php 实例说明 socket通信机制   PHP Socket 教學

    一,socket是什么

    什么是socket 所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。说白了就是一种通信机制。它类似于银行,电信啊这些部分的电话客服部门。你打电话的时候,那边会分配置一个人回答你的问题,客服部门就相当于socket的服务器端了,你这边呢就相当于客户端了,在和你通话结束前,如果有人在想找和你通话的那个说话,是不可能的,因为你在和他通信,当然客服部门的电话交换机也不会重复分配。

    下面我将举例子来说明一下,socket是怎么工作的。如果你是基于应用层开发的人员并不一定要理解原理,但是能知道那是更好了。网上有关于socket的php api。下下来用就行了。

    二,socket服务器server.php

     1 <?php  
     2 // 建立server端socket  
     3 $tcp = getprotobyname("tcp");  
     4 $socket = socket_create(AF_INET, SOCK_STREAM, $tcp);  
     5 socket_bind($socket, '127.0.0.1', 10008);       //绑定要监听的端口  
     6 socket_listen($socket);       //监听端口  
     7   
     8 //初始化一个数据,和客户端通信  
     9 $buffer = "connect";  
    10 while (true) {  
    11     // 接受一个socket连接  
    12     $connection = socket_accept($socket);  
    13     if(!$connection){  
    14         echo "connect fail";  
    15     }else{  
    16             echo "Socket connected\n";  
    17             // 向客户端传递一个信息数据  
    18             if ($buffer != "") {  
    19                 echo "send data to client\n";  
    20                 socket_write($connection, $buffer . "\n");  
    21                 echo "Wrote to socket\n";  
    22             } else {  
    23                 echo "no data in the buffer\n" ;  
    24             }  
    25             // 从客户端取得信息  
    26             while ($data = @socket_read($connection, 1024, PHP_NORMAL_READ)) {  
    27                     printf("Buffer: " . $data . "\n");  
    28                     //取得信息给客户端一个反馈  
    29                     socket_write($connection, "Information Received\n");  
    30             }  
    31     }  
    32   
    33     socket_close($connection);  
    34     //关闭 socket  
    35     printf("Closed the socket\n");  
    36 }  
    37 ?>  

    三,socket客户端client.php

     1 <?php  
     2 // 建立客户端的socet连接  
     3 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);  
     4 $connection = socket_connect($socket, '127.0.0.1', 10008);    //连接服务器端socket  
     5   
     6 while ($buffer = @socket_read($socket, 1024, PHP_NORMAL_READ)) {  
     7     //服务端告诉客户端,自己的状态  
     8     if (preg_match("/not connect/",$buffer)) {  
     9         echo "don`t connect\n";  
    10         break;  
    11     } else {  
    12         //服务器传来信息  
    13         echo "Buffer Data: " . $buffer . "\n";  
    14   
    15         echo "Writing to Socket\n";  
    16         // 将客户的信息写到通道中,传给服务器端  
    17         if (!socket_write($socket, "SOME DATA\n")) {  
    18             echo "Write failed\n";  
    19         }  
    20         //服务器端收到信息后,给于的回应信息  
    21         while ($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)) {  
    22                 echo "sent to server: SOME DATA\n response from server was:" . $buffer . "\n";  
    23         }         
    24   
    25     }  
    26 }  
    27   
    28 ?>  

    四,通信机制的一个图片(不考虑等待时间结束自动关闭socket)

     

    简单说明一下,在说明前我要说一下,为什么要用php命令来执行服务器和客户端,客户端你用fsockopen,这样就在流览器上访问了,不至少于会连接超时。为什么会这样呢,因为你创建一个socket时,它会不断的去监听客户有没有要来连接。

    socket通信的建立要二个socket通道,一个是服务器端创建的,一个是客户端创建的。

    1号线,服务器创建一个socket通道,并将信息放到缓存,等待客户端连接

    2号线,客户端创建一个socket通道,并连接服务器端,取得服务器端的信息进行通信,将要传的信息送入通道

    3号线,服务器端从客户端取得信息,并告诉客户端,信息我已经收到了。将要传的信息送入通道

    4号线,客户端从服务器端取得确认信息

    到此一个通信就完全建立了,数据传输完毕后,服务器端会断开socket通信,具体操作如下

    1,运行socket服务器端

    [root@BlackGhost zhangy]# /usr/local/php/bin/php -a /home/zhangy/www/test2/server.php
    Interactive mode enabled

    这一点做了那些工作呢

    a,监听了一个10008端口

    [zhangy@BlackGhost ~]$ netstat -an |grep LISTEN |grep 10008
    tcp        0      0 127.0.0.1:10008         0.0.0.0:*               LISTEN
    [zhangy@BlackGhost ~]$

    b,将信息送到缓存里面

    $buffer = "connect";看上面的代码
    
    2,运行socket客户端
    [root@BlackGhost zhangy]# /usr/local/php/bin/php -a /home/zhangy/www/test2/client.php
    Interactive mode enabled
    
    Buffer Data: connect
    
    Writing to Socket
    sent to server: SOME DATA
     response from server was:Information Received
    
    3,回到服务器端
    [root@BlackGhost zhangy]# /usr/local/php/bin/php -a /home/zhangy/www/test2/server.php
    Interactive mode enabled
    
    Socket connected
    send data to client
    Wrote to socket
    Buffer: SOME DATA
    
    Closed the socket

    来自另外一篇博客

    ◆ Socket 基礎

    PHP 使用Berkley的socket庫來創建它的連接。你可以知道socket只不過是一個數據結構。你使用這個socket數據結構去開始一個客戶端和服 務器之間的會話。這個服務器是一直在監聽準備產生一個新的會話。當一個客戶端連接服務器,它就打開服務器正在進行監聽的一個端口進行會話。這時,服務器端 接受客戶端的連接請求,那麼就進行一次循環。現在這個客戶端就能夠發送信息到服務器,服務器也能發送信息給客戶端。

    產生一個Socket,你需要三個變量:一個協議、一個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_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()    

    寫數據到分散/聚合數組

    以上所有的函數都是PHP中關於socket的,使用這些函數,你必須把你的socket打開,如果你沒有打開,請編輯你的php.ini文件,去掉下面這行前面的註釋:
    extension=php_sockets.dll
    如果你無法去掉註釋,那麼請使用下面的代碼來加載擴展庫:

    1 <?php
    2 if(!extension_loaded('sockets')) {
    3     if(strtoupper(substr(PHP_OS, 3)) == 「WIN」) {
    4         dl('php_sockets.dll');
    5     } else {
    6         dl('sockets.so');
    7     }
    8 }
    9 ?>

    ◆ 產生一個服務器

    現在我們把第一個例子進行完善。你需要監聽一個指定的socket並且處理用戶的連接。

     1 <?php
     2 $commonProtocol = getprotobyname("tcp");
     3 $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
     4 socket_bind($socket, 'localhost', 1337);
     5 socket_listen($socket);
     6 // Accept any incoming connections to the server
     7 $connection = socket_accept($socket);
     8 if($connection)
     9 {
    10  socket_write($connection, "You have connected to the socket...\n\r"); 
    11 } 
    12 ?>

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

    set_time_limit(0);

    上面的服務器端有三個問題:

    1. 它不能接受多個連接。

    2. 它只完成唯一的一個命令。

    3. 你不能通過Web瀏覽器連接這個服務器。

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

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

     1 <?php
     2 // Set up our socket
     3 $commonProtocol = getprotobyname("tcp");
     4 $socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
     5 socket_bind($socket, 'localhost', 1337);
     6 socket_listen($socket);
     7 // Initialize the buffer
     8 $buffer = "NO DATA";
     9 while(true)
    10 {
    11  // Accept any connections coming in on this socket
    12  $connection = socket_accept($socket);
    13  printf("Socket connected\r\n");
    14  // Check to see if there is anything in the buffer
    15  if($buffer != "")
    16  {
    17   printf("Something is in the buffer...sending data...\r\n");
    18   socket_write($connection, $buffer . "\r\n");
    19   printf("Wrote to socket\r\n");
    20  }
    21  else
    22  {
    23   printf("No Data in the buffer\r\n");
    24  }
    25  // Get the input
    26  while($data = socket_read($connection, 1024, PHP_NORMAL_READ))
    27  {
    28   $buffer = $data;
    29   socket_write($connection, "Information Received\r\n");
    30   printf("Buffer: " . $buffer . "\r\n");
    31  }
    32  socket_close($connection);
    33  printf("Closed the socket\r\n\r\n");
    34 }
    35 ?>

    這 個服務器端要做什麼呢?它初始化一個socket並且打開一個緩存收發數據。它等待連接,一旦產生一個連接,它將打印「Socket connected」在服務器端的屏幕上。這個服務器檢查緩衝區,如果緩衝區裡有數據,它將把數據發送到連接過來的計算機。然後它發送這個數據的接受信 息,一旦它接受了信息,就把信息保存到數據裡,並且讓連接的計算機知道這些信息,最後關閉連接。當連接關閉後,服務器又開始處理下一次連接。(翻譯的爛, 附上原文)


    This is what the server does. It initializes the socket and the buffer that you use to receive
    and send data. Then it waits for a connection. Once a connection is created it prints
    「Socket connected」 to the screen the server is running on. The server then checks to see if
    there is anything in the buffer; if there is, it sends the data to the connected computer.
    After it sends the data it waits to receive information. Once it receives information it stores
    it in the data, lets the connected computer know that it has received the information, and
    then closes the connection. After the connection is closed, the server starts the whole
    process again.

    ◆ 產生一個客戶端

    處理第二個問題是很容易的。你需要產生一個php頁連接一個socket,發送一些數據進它的緩存並處理它。然後你又個處理後的數據在還頓,你能夠發送你的數據到服務器。在另外一台客戶端連接,它將處理那些數據。
    To solve the second problem is very easy. You need to create a PHP page that connects to
    a socket, receive any data that is in the buffer, and process it. After you have processed the
    data in the buffer you can send your data to the server. When another client connects, it
    will process the data you sent and the client will send more data back to the server.
     1 <?php
     2 // Create the socket and connect
     3 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
     4 $connection = socket_connect($socket,'localhost', 1337);
     5 while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
     6 {
     7  if($buffer == 'NO DATA')
     8  {
     9  echo('<p>NO DATA</p>');
    10  break;
    11  }
    12  else
    13  {
    14   // Do something with the data in the buffer
    15   echo('<p>Buffer Data: ' . $buffer . '</p>');
    16  }
    17 }
    18 echo('<p>Writing to Socket</p>');
    19 // Write some test data to our socket
    20 if(!socket_write($socket, 'SOME DATA\r\n'))
    21 {
    22  echo('<p>Write failed</p>');
    23 }
    24 // Read any response from the socket
    25 while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)){
    26 echo('<p>Data sent was: SOME DATA<br> Response was:' . $buffer . '</p>');
    27 }
    28 echo('<p>Done Reading from Socket</p>');
    29 ?>

    這個例子的代碼演示了客戶端連接到服務器。客戶端讀取數據。如果這是第一時間到達這個循環的首次連接,這個服務器將發送「NO DATA」返回給客戶端。如果情況發生了,這個客戶端在連接之上。客戶端發送它的數據到服務器,數據發送給服務器,客戶端等待響應。一旦接受到響應,那麼 它將把響應寫到屏幕上。

     
  • 相关阅读:
    poi 导出Excel
    【EasyUI】combotree和combobox模糊查询
    多线程和Socket套接字
    io流
    前端页面的语法 jquery javascript ajax
    spring+mybatis
    Exchanger 原理
    CountDownLatch、CyclicBarrier和 Semaphore
    sleep() 、join()、yield()有什么区别
    创建线程的方式及实现
  • 原文地址:https://www.cnblogs.com/zjfazc/p/3055080.html
Copyright © 2020-2023  润新知