亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > PHP > 正文

PHP SOCKET編程詳解

2024-05-04 23:35:29
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了PHP SOCKET編程詳解,需要的朋友可以參考下

1. 預備知識

一直以來很少看到有多少人使用php的socket模塊來做一些事情,大概大家都把它定位在腳本語言的范疇內吧,但是其實php的socket模塊可以做很多事情,包括做ftplist,http post提交,smtp提交,組包并進行特殊報文的交互(如smpp協議),whois查詢。這些都是比較常見的查詢。

特別是php的socket擴展庫可以做的事情簡直不會比c差多少。

php的socket連接函數

1、集成于內核的socket

這個系列的函數僅僅只能做主動連接無法實現端口監聽相關的功能。而且在4.3.0之前所有socket連接只能工作在阻塞模式下。

此系列函數包括

fsockopen,pfsockopen

這兩個函數的具體信息可以查詢php.net的用戶手冊

他們均會返回一個資源編號對于這個資源可以使用幾乎所有對文件操作的函數對其進行操作如fgets(),fwrite(), fclose()等單注意的是所有函數遵循這些函數面對網絡信息流時的規律,例如:

fread() 從文件指針 handle 讀取最多 length 個字節。 該函數在讀取完 length 個字節數,或到達 EOF 的時候,或(對于網絡流)當一個包可用時就會停止讀取文件,視乎先碰到哪種情況。

可以看出對于網絡流就必須注意取到的是一個完整的包就停止。

2、php擴展模塊帶有的socket功能。

php4.x 以后有這么一個模塊extension=php_sockets.dll,Linux上是一個extension=php_sockets.so。

當打開這個此模塊以后就意味著php擁有了強大的socket功能,包括listen端口,阻塞及非阻塞模式的切換,multi-client 交互式處理等

這個系列的函數列表參看http://www.php.net/manual/en/ref.sockets.php

看過這個列表覺得是不是非常豐富呢?不過非常遺憾這個模塊還非常年輕還有很多地方不成熟,相關的參考文檔也非常少:(

我也正在研究中,因此暫時不具體討論它,僅給大家一個參考文章

http://www.zend.com/pecl/tutorials/sockets.php

2. 使用PHP socket擴展

服務器端代碼:

 

 
  1. <?php  
  2. /**  
  3. * File name server.php  
  4. * 服務器端代碼  
  5.  
  6. * @author guisu.huang  
  7. * @since 2012-04-11  
  8.  
  9. */ 
  10.  
  11. //確保在連接客戶端時不會超時  
  12. set_time_limit(0);  
  13. //設置IP和端口號  
  14. $address = "127.0.0.1";  
  15. $port = 2046; //調試的時候,可以多換端口來測試程序!  
  16. /**  
  17. * 創建一個SOCKET  
  18. * AF_INET=是ipv4 如果用ipv6,則參數為 AF_INET6  
  19. * SOCK_STREAM為socket的tcp類型,如果是UDP則使用SOCK_DGRAM  
  20. */ 
  21. $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() 失敗的原因是:" . socket_strerror(socket_last_error()) . "/n");  
  22. //阻塞模式  
  23. socket_set_block($sockor die("socket_set_block() 失敗的原因是:" . socket_strerror(socket_last_error()) . "/n");  
  24. //綁定到socket端口  
  25. $result = socket_bind($sock$address$portor die("socket_bind() 失敗的原因是:" . socket_strerror(socket_last_error()) . "/n");  
  26. //開始監聽  
  27. $result = socket_listen($sock, 4) or die("socket_listen() 失敗的原因是:" . socket_strerror(socket_last_error()) . "/n");  
  28. echo "OK/nBinding the socket on $address:$port ... ";  
  29. echo "OK/nNow ready to accept connections./nListening on the socket ... /n";  
  30. do { // never stop the daemon  
  31. //它接收連接請求并調用一個子連接Socket來處理客戶端和服務器間的信息  
  32. $msgsock = socket_accept($sockor die("socket_accept() failed: reason: " . socket_strerror(socket_last_error()) . "/n");  
  33.  
  34. //讀取客戶端數據  
  35. echo "Read client data /n";  
  36. //socket_read函數會一直讀取客戶端數據,直到遇見/n,/t或者/0字符.PHP腳本把這寫字符看做是輸入的結束符.  
  37. $buf = socket_read($msgsock, 8192);  
  38. echo "Received msg: $buf /n";  
  39.  
  40. //數據傳送 向客戶端寫入返回結果  
  41. $msg = "welcome /n";  
  42. socket_write($msgsock$msgstrlen($msg)) or die("socket_write() failed: reason: " . socket_strerror(socket_last_error()) ."/n");  
  43. //一旦輸出被返回到客戶端,父/子socket都應通過socket_close($msgsock)函數來終止  
  44. socket_close($msgsock);  
  45. while (true);  
  46. socket_close($sock); 

客戶端代碼:

 

 
  1. <?php  
  2. /**  
  3. * File name:client.php  
  4. * 客戶端代碼  
  5.  
  6. * @author guisu.huang  
  7. * @since 2012-04-11  
  8. */ 
  9. set_time_limit(0);  
  10.  
  11. $host = "127.0.0.1";  
  12. $port = 2046;  
  13. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)or die("Could not create socket/n"); // 創建一個Socket  
  14.  
  15. $connection = socket_connect($socket$host$portor die("Could not connet server/n"); // 連接  
  16. socket_write($socket"hello socket"or die("Write failed/n"); // 數據傳送 向服務器發送消息  
  17. while ($buff = socket_read($socket, 1024, PHP_NORMAL_READ)) {  
  18. echo("Response was:" . $buff . "/n");  
  19. }  
  20. socket_close($socket);  

使用cli方式啟動server:

php server.php

這里注意socket_read函數:

可選的類型參數是一個命名的常數:

PHP_BINARY_READ - 使用系統recv()函數。用于讀取二進制數據的安全。 (在PHP>“默認= 4.1.0)

PHP_NORMAL_READ - 讀停在/ n或/r(在PHP <= 4.0.6默認)

針對參數PHP_NORMAL_READ ,如果服務器的響應結果沒有/ n。造成socket_read(): unable to read from socket

3. PHP socket內部源碼

從PHP內部源碼來看,PHP提供的socket編程是在socket,bind,listen等函數外添加了一個層,讓其更加簡單和方便調用。但是一些業務邏輯的程序還是需要程序員自己去實現。

下面我們以socket_create的源碼實現來說明PHP的內部實現。

前面我們有說到php的socket是以擴展的方式實現的。在源碼的ext目錄,我們找到sockets目錄。這個目錄存放了PHP對于socket的實現。直接搜索PHP_FUNCTION(socket_create),在sockets.c文件中找到了此函數的實現。如下所示代碼:

 

 
  1. /* {{{ proto resource socket_create(int domain, int type, int protocol) U  
  2. Creates an endpoint for communication in the domain specified by domain, of type specified by type */ 
  3. PHP_FUNCTION(socket_create)  
  4. {  
  5. long arg1, arg2, arg3;  
  6. php_socket *php_sock = (php_socket*)emalloc(sizeof(php_socket));  
  7.  
  8. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {  
  9. efree(php_sock);  
  10. return;  
  11. }  
  12.  
  13. if (arg1 != AF_UNIX  
  14. #if HAVE_IPV6  
  15. && arg1 != AF_INET6  
  16. #endif  
  17. && arg1 != AF_INET) {  
  18. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", arg1);  
  19. arg1 = AF_INET;  
  20. }  
  21.  
  22. if (arg2 > 10) {  
  23. php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", arg2);  
  24. arg2 = SOCK_STREAM;  
  25. }  
  26.  
  27. php_sock->bsd_socket = socket(arg1, arg2, arg3);  
  28. php_sock->type = arg1;  
  29.  
  30. if (IS_INVALID_SOCKET(php_sock)) {  
  31. SOCKETS_G(last_error) = errno;  
  32. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, php_strerror(errno TSRMLS_CC));  
  33. efree(php_sock);  
  34. RETURN_FALSE;  
  35. }  
  36.  
  37. php_sock->error = 0;  
  38. php_sock->blocking = 1;  
  39. 1257,1-8 61%  
  40. ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);  

Zend API實際對c函數socket做了包裝,供PHP使用。 而在c的socket編程中,我們使用如下方式初始化socket。

 

 
  1. //初始化Socket  
  2. if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){  
  3. printf("create socket error: %s(errno: %d)/n",strerror(errno),errno);  
  4. exit(0);  

4. 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() 寫數據到分散/聚合數組

5. PHP Socket模擬請求

我們使用stream_socket來模擬:

 

 
  1. /**  
  2.  
  3. * @param $data= array=array('key'=>value)  
  4. */ 
  5. function post_contents($data = array()) {  
  6. $post = $data ? http_build_query($data) : '';  
  7. $header = "POST /test/ HTTP/1.1" . "/n";  
  8. $header .= "User-Agent: Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1)" . "/n";  
  9. $header .= "Host: localhost" . "/n";  
  10. $header .= "Accept: */*" . "/n";  
  11. $header .= "Referer: http://localhost/test/" . "/n";  
  12. $header .= "Content-Length: "strlen($post) . "/n";  
  13. $header .= "Content-Type: application/x-www-form-urlencoded" . "/n";  
  14. $header .= "/r/n";  
  15. $ddd = $header . $post;  
  16. $fp = stream_socket_client("tcp://localhost:80"$errno$errstr, 30);  
  17. $response = '';  
  18. if (!$fp) {  
  19. echo "$errstr ($errno)<br />/n";  
  20. else {  
  21. fwrite($fp$ddd);  
  22. $i = 1;  
  23. while ( !feof($fp) ) {  
  24. $r = fgets($fp, 1024);  
  25. $response .= $r;  
  26. //處理這一行  
  27. }  
  28. }  
  29. fclose($fp);  
  30. return $response;  

注意,以上程序可能會進入死循環;

這個PHP的feof($fp) 需要注意的地方了,我們來分析為什么進入死循環。

 

 
  1. while ( !feof($fp) ) {  
  2. $r = fgets($fp, 1024);  
  3. $response .= $r;  
  4. }  

實際上,feof是可靠的,但是結合fgets函數一塊使用的時候,必須要小心了。一個常見的做法是:

 

 
  1. $fp = fopen("myfile.txt""r");  
  2. while (!feof($fp)) {  
  3. $current_line = fgets($fp);  
  4. //對結果做進一步處理,防止進入死循環  

當處理純文本的時候,fgets獲取最后一行字符后,foef函數返回的結果并不是TRUE。實際的運算過程如下:

1) while()繼續循環。

2) fgets 獲取倒數第二行的字符串

3) feof返回false,進入下一次循環

4)fgets獲取最后一行數據

5) 一旦fegets函數被調用,feof函數仍然返回的是false。所以繼續執行循環

6) fget試圖獲取另外一行,但實際結果是空的。實際代碼沒有意識到這一點,試圖處理另外根本不存在的一行,但fgets被調用了,feof放回的結果仍然是false

7) .....

8) 進入死循環

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久中文| 国产精品九九九| 97视频免费看| 日韩精品电影网| 欧美激情一区二区久久久| 亚洲激情 国产| 欧美日韩国产精品一区二区不卡中文| 亚洲天堂影视av| 国产精品美乳一区二区免费| 国产精品99久久久久久白浆小说| 亚洲伊人久久大香线蕉av| www.日韩免费| 伊人亚洲福利一区二区三区| 精品欧美aⅴ在线网站| 久久成人精品一区二区三区| 欧美大全免费观看电视剧大泉洋| 欧美激情一级欧美精品| 国产在线观看一区二区三区| 亚洲日本欧美日韩高观看| 国产精品专区一| 欧美福利视频在线观看| 国产精品h片在线播放| 日韩视频免费在线| 97精品国产97久久久久久春色| 91牛牛免费视频| 狠狠操狠狠色综合网| 久久天天躁狠狠躁夜夜躁2014| 成人欧美一区二区三区在线湿哒哒| 亚洲国产97在线精品一区| 欧美精品videossex性护士| 亚洲激情在线观看视频免费| 久久伊人91精品综合网站| 91精品视频免费| 日本午夜在线亚洲.国产| 成人性生交xxxxx网站| 久久99精品视频一区97| 欧美精品xxx| 国产精品久久77777| 欧美激情综合色综合啪啪五月| 日韩欧美在线视频免费观看| 国产精品视频区1| 国产精品一区二区久久国产| 国产精品91久久久| 日韩欧美中文第一页| 日本韩国欧美精品大片卡二| 亚洲石原莉奈一区二区在线观看| 欧洲成人午夜免费大片| 国产精品影院在线观看| 亚洲精品国产美女| 亚洲国产欧美自拍| 国产一区私人高清影院| 色噜噜狠狠狠综合曰曰曰| 精品国产福利视频| 亚洲高清av在线| 琪琪亚洲精品午夜在线| 国产精品视频一区二区高潮| 国产精品久久久久久网站| 欧美一区在线直播| 日本免费一区二区三区视频观看| 日韩欧美黄色动漫| yw.139尤物在线精品视频| 国产乱人伦真实精品视频| 日韩在线激情视频| 欧美中文在线字幕| 亚洲福利视频网站| 午夜精品久久久久久99热| 揄拍成人国产精品视频| 久久久久国产精品免费| 日韩av网站在线| 国产91热爆ts人妖在线| 欧美黑人一级爽快片淫片高清| 国产精品久久91| 欧美中文字幕在线播放| 国内精品久久久久久久| 亚洲一区制服诱惑| 国产亚洲人成a一在线v站| 中文字幕av一区| 国产成人亚洲综合| 欧美在线播放视频| 91精品国产91| 中文国产成人精品| 国产在线精品自拍| 欧美日韩精品在线视频| 中日韩美女免费视频网站在线观看| 国产精品嫩草视频| 久久成人人人人精品欧| 米奇精品一区二区三区在线观看| 91精品国产高清久久久久久久久| 日韩av成人在线观看| 欧美在线视频一区二区| 久久久欧美精品| 亚洲视频在线播放| 黑人狂躁日本妞一区二区三区| 亚洲www在线观看| 午夜精品理论片| 久久国产精品偷| 欧美日韩国产精品| 亚洲最大成人免费视频| 国产欧美精品va在线观看| 国产精品电影久久久久电影网| 亚洲欧美国产日韩天堂区| 日韩国产高清污视频在线观看| 国产在线精品一区免费香蕉| 热久久免费视频精品| 国内精品小视频| 亚洲一区二区久久久久久久| 色樱桃影院亚洲精品影院| 欧美亚洲午夜视频在线观看| 欧美性受xxx| 久久激情视频免费观看| 日本不卡免费高清视频| 亚洲欧美激情一区| 国产日产久久高清欧美一区| 亚洲精品按摩视频| 伊人伊人伊人久久| 欧美午夜视频在线观看| xvideos亚洲人网站| 久久精品国产一区二区电影| 亚洲va男人天堂| 亚洲精品欧美日韩| 97**国产露脸精品国产| 欧美床上激情在线观看| 国产精品成人va在线观看| 国产一区二区三区在线观看视频| 福利一区福利二区微拍刺激| 亚洲天堂网站在线观看视频| 中文欧美日本在线资源| 亚洲视频自拍偷拍| 欧美一级大片在线观看| 国产精品视频久| 68精品国产免费久久久久久婷婷| 亚洲精品日韩久久久| 色偷偷av亚洲男人的天堂| 911国产网站尤物在线观看| 亚洲一区二区三区久久| 人人爽久久涩噜噜噜网站| 中文字幕精品一区二区精品| 久久精品亚洲一区| 久久成人一区二区| 欧美日韩一区二区三区| 久久99国产精品久久久久久久久| 最新国产成人av网站网址麻豆| 91沈先生作品| 91精品国产高清久久久久久| 在线观看视频99| 97久久精品人搡人人玩| 国内免费精品永久在线视频| 亚洲国产精品久久久久久| 日韩电影中文字幕在线观看| 日韩免费在线观看视频| 热久久美女精品天天吊色| 97精品欧美一区二区三区| 久久综合亚洲社区| 国产日韩在线看| 最近2019中文字幕第三页视频| 欧美性在线视频| 亚洲最大av网站| 日韩av在线最新| 国产国产精品人在线视| 欧美日韩在线视频观看| 91免费国产网站| 69**夜色精品国产69乱| 国产欧美日韩中文字幕| 精品福利视频导航|