PHP的Socket編程

來源:互聯網
上載者:User
from: http://www.phppan.com/2011/02/php-socket/

PHP的Socket編程

電腦進程可以使用socket和其他進程通訊,通過socket,其他進程的位置是透明的。這些進程可以在同一台電腦上也可以在不同的電腦上。

在PHP中,socket是以擴充的方式載入的,如果無法使用socket相關函數,請確認是否有開啟此擴充。
下面我們以一個連線導向的用戶端和伺服器的簡單實現說明一些函數的使用,在此之後,簡單介紹在PHP的內部是如何?這些函數的。

【用戶端實現】
如下所示代碼為用戶端的實現代碼:

set_time_limit(0); $host = "127.0.0.1";$port = 2046; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)or die("Could not createsocket\n"); // 建立一個Socket $connection = socket_connect($socket, $host, $port) or die("Could not connet server\n");    //  串連 socket_write($socket, "time") or die("Write failed\n"); // 資料傳送 向伺服器發送訊息 while ($buffer = socket_read($socket, 1024, PHP_NORMAL_READ)) {    echo("Data sent was: time\nResponse was:" . $buffer . "\n");} socket_close($socket);

用戶端首先建立一個socket,並且串連伺服器。向伺服器發送一個time的訊息,等待伺服器返回資訊,讀取伺服器的資訊並輸出。

【伺服器實現】

 set_time_limit(0); $host = "127.0.0.1";$port = 2046; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Could not createsocket\n"); // 建立一個Socket $result = socket_bind($socket, $host, $port) or die("Could not bind tosocket\n"); //綁定Socket到連接埠 $result = socket_listen($socket, 3) or die("Could not set up socket listener\n"); // 開始監聽串連 $spawn = socket_accept($socket) or die("Could not accept incoming connection\n"); // 處理通訊 $input = socket_read($spawn, 1024) or die("Could not read input\n"); // 資料傳送 獲得用戶端的輸入 $input = trim($input);echo 'input:', $input, "\n"; if ($input == 'time') {    $output = date("Y-m-d H:i:s"). "\n"; //處理用戶端輸入並返回結果}else{    $output = "input error \n"; //處理用戶端輸入並返回結果} echo "output:", $output, "\n"; //資料傳送 向用戶端寫入返回結果socket_write($spawn, $output, strlen($output)) or die("Could not write output\n"); // 關閉socketssocket_close($spawn);socket_close($socket);

伺服器端建立一個socket,並且綁定連接埠,監聽串連,讀取用戶端的資料,根據用戶端的輸入返回不同的值,最後寫入資料到用戶端。關閉socket。
只是這個伺服器不能接受多個串連並且只完成一個操作
【PHP內部源碼說明】
從PHP內部源碼來看,PHP提供的socket編程是在socket,bind,listen等函數外添加了一個層,讓其更加簡單和方便調用。但是一些商務邏輯的程式還是需要程式員自己去實現。
下面我們以socket_create的源碼實現來說明PHP的內部實現。
前面我們有說到php的socket是以擴充的方式實現的。在源碼的ext目錄,我們找到sockets目錄。這個目錄存放了PHP對於socket的實現。直接搜尋PHP_FUNCTION(socket_create),在sockets.c檔案中找到了此函數的實現。如下所示代碼:

/* {{{ proto resource socket_create(int domain, int type, int protocol) U   Creates an endpoint for communication in the domain specified by domain, of type specified by type */PHP_FUNCTION(socket_create){        long            arg1, arg2, arg3;        php_socket      *php_sock = (php_socket*)emalloc(sizeof(php_socket));         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &arg1, &arg2, &arg3) == FAILURE) {                efree(php_sock);                return;        }         if (arg1 != AF_UNIX#if HAVE_IPV6                && arg1 != AF_INET6#endif                && arg1 != AF_INET) {                php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket domain [%ld] specified for argument 1, assuming AF_INET", arg1);                arg1 = AF_INET;        }         if (arg2 > 10) {                php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid socket type [%ld] specified for argument 2, assuming SOCK_STREAM", arg2);                arg2 = SOCK_STREAM;        }         php_sock->bsd_socket = socket(arg1, arg2, arg3);        php_sock->type = arg1;         if (IS_INVALID_SOCKET(php_sock)) {                SOCKETS_G(last_error) = errno;                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, php_strerror(errno TSRMLS_CC));                efree(php_sock);                RETURN_FALSE;        }         php_sock->error = 0;        php_sock->blocking = 1;                                                                                                                                           1257,1-8      61%        ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);}/* }}} */

從整個函數的實現看,程式基本上是一個錯誤和異常處理。PHP本身引入了php_socket結構體,其建立時調用socket函數實現。

PS:關於PHP的網路編程,我們會在TIPI系列文章中作詳細的說明。
【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個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.