天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

深入php socket的講解與實(shí)例分析

在這一章里你將了解到迷人而又讓人容易糊涂的套接字(Sockets)。Sockets在php中是沒有充分利用的功能。今天你將看到產(chǎn)生一個(gè)能使用客戶端連接的服務(wù)器,并在客戶端使用socket進(jìn)行連接,服務(wù)器端將詳細(xì)的處理信息發(fā)送給客戶端。
當(dāng)你看到完整的socket過程,那么你將會在以后的程序開發(fā)中使用它。這個(gè)服務(wù)器是一個(gè)能讓你連接的HTTP服務(wù)器,客戶端是一個(gè)Web瀏覽器,這是一個(gè)單一的 客戶端/服務(wù)器 的關(guān)系。

◆ Socket 基礎(chǔ)
php使用Berkley的socket庫來創(chuàng)建它的連接。你可以知道socket只不過是一個(gè)數(shù)據(jù)結(jié)構(gòu)。你使用這個(gè)socket數(shù)據(jù)結(jié)構(gòu)去開始一個(gè)客戶端和服務(wù)器之間的會話。這個(gè)服務(wù)器是一直在監(jiān)聽準(zhǔn)備產(chǎn)生一個(gè)新的會話。當(dāng)一個(gè)客戶端連接服務(wù)器,它就打開服務(wù)器正在進(jìn)行監(jiān)聽的一個(gè)端口進(jìn)行會話。這時(shí),服務(wù)器端接受客戶端的連接請求,那么就進(jìn)行一次循環(huán)。現(xiàn)在這個(gè)客戶端就能夠發(fā)送信息到服務(wù)器服務(wù)器也能發(fā)送信息給客戶端。
產(chǎn)生一個(gè)Socket,你需要三個(gè)變量:一個(gè)協(xié)議、一個(gè)socket類型和一個(gè)公共協(xié)議類型。產(chǎn)生一個(gè)socket有三種協(xié)議供選擇,繼續(xù)看下面的內(nèi)容來獲取詳細(xì)的協(xié)議內(nèi)容。
定義一個(gè)公共的協(xié)議類型是進(jìn)行連接一個(gè)必不可少的元素。下面的表我們看看有那些公共的協(xié)議類型。

表一:協(xié)議
名字/常量 描述
AF_INET 這是大多數(shù)用來產(chǎn)生socket的協(xié)議,使用TCP或UDP來傳輸,用在IPv4的地址
AF_INET6 與上面類似,不過是來用在IPv6的地址
AF_UNIX 本地協(xié)議,使用在Unix和Linux系統(tǒng)上,它很少使用,一般都是當(dāng)客戶端和服務(wù)器在同一臺及其上的時(shí)候使用

表二:Socket類型
名字/常量 描述
SOCK_STREAM 這個(gè)協(xié)議是按照順序的、可靠的、數(shù)據(jù)完整的基于字節(jié)流的連接。這是一個(gè)使用最多的socket類型,這個(gè)socket是使用TCP來進(jìn)行傳輸。
SOCK_DGRAM 這個(gè)協(xié)議是無連接的、固定長度的傳輸調(diào)用。該協(xié)議是不可靠的,使用UDP來進(jìn)行它的連接。
SOCK_SEQPACKET 這個(gè)協(xié)議是雙線路的、可靠的連接,發(fā)送固定長度的數(shù)據(jù)包進(jìn)行傳輸。必須把這個(gè)包完整的接受才能進(jìn)行讀取。
SOCK_RAW 這個(gè)socket類型提供單一的網(wǎng)絡(luò)訪問,這個(gè)socket類型使用ICMP公共協(xié)議。(ping、traceroute使用該協(xié)議)
SOCK_RDM 這個(gè)類型是很少使用的,在大部分的操作系統(tǒng)上沒有實(shí)現(xiàn),它是提供給數(shù)據(jù)鏈路層使用,不保證數(shù)據(jù)包的順序

表三:公共協(xié)議
名字/常量 描述
ICMP 互聯(lián)網(wǎng)控制消息協(xié)議,主要使用在網(wǎng)關(guān)和主機(jī)上,用來檢查網(wǎng)絡(luò)狀況和報(bào)告錯(cuò)誤信息
UDP 用戶數(shù)據(jù)報(bào)文協(xié)議,它是一個(gè)無連接,不可靠的傳輸協(xié)議
TCP 傳輸控制協(xié)議,這是一個(gè)使用最多的可靠的公共協(xié)議,它能保證數(shù)據(jù)包能夠到達(dá)接受者那兒,如果在傳輸過程中發(fā)生錯(cuò)誤,那么它將重新發(fā)送出錯(cuò)數(shù)據(jù)包。

現(xiàn)在你知道了產(chǎn)生一個(gè)socket的三個(gè)元素,那么我們就在php中使用socket_create()函數(shù)來產(chǎn)生一個(gè)socket。這個(gè)socket_create()函數(shù)需要三個(gè)參數(shù):一個(gè)協(xié)議、一個(gè)socket類型、一個(gè)公共協(xié)議。socket_create()函數(shù)運(yùn)行成功返回一個(gè)包含socket的資源類型,如果沒有成功則返回false。
Resourece socket_create(int protocol, int socketType, int commonProtocol);

現(xiàn)在你產(chǎn)生一個(gè)socket,然后呢?php提供了幾個(gè)操縱socket的函數(shù)。你能夠綁定socket到一個(gè)IP,監(jiān)聽一個(gè)socket的通信,接受一個(gè)socket;現(xiàn)在我們來看一個(gè)例子,了解函數(shù)是如何產(chǎn)生、接受和監(jiān)聽一個(gè)socket。
復(fù)制代碼 代碼如下:
<?php
$commonProtocol = getprotobyname(“tcp”);
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, ‘localhost', 1337);
socket_listen($socket);
// More socket functionality to come
?>

上面這個(gè)例子產(chǎn)生一個(gè)你自己的服務(wù)器端。例子第一行,
$commonProtocol = getprotobyname(“tcp”);
使用公共協(xié)議名字來獲取一個(gè)協(xié)議類型。在這里使用的是TCP公共協(xié)議,如果你想使用UDP或者ICMP協(xié)議,那么你應(yīng)該把getprotobyname()函數(shù)的參數(shù)改為“udp”或“icmp”。還有一個(gè)可選的辦法是不使用getprotobyname()函數(shù)而是指定SOL_TCP或SOL_UDP在socket_create()函數(shù)中。
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
例子的第二行是產(chǎn)生一個(gè)socket并且返回一個(gè)socket資源的實(shí)例。在你有了一個(gè)socket資源的實(shí)例以后,你就必須把socket綁定到一個(gè)IP地址和某一個(gè)端口上。
socket_bind($socket, ‘localhost', 1337);
在這里你綁定socket到本地計(jì)算機(jī)(127.0.0.1)和綁定socket到你的1337端口。然后你就需要監(jiān)聽所有進(jìn)來的socket連接。
socket_listen($socket);
在第四行以后,你就需要了解所有的socket函數(shù)和他們的使用。

表四:Socket函數(shù)
函數(shù)名 描述
socket_accept() 接受一個(gè)Socket連接
socket_bind() 把socket綁定在一個(gè)IP地址和端口上
socket_clear_error() 清除socket的錯(cuò)誤或者最后的錯(cuò)誤代碼
socket_close() 關(guān)閉一個(gè)socket資源
socket_connect() 開始一個(gè)socket連接
socket_create_listen() 在指定端口打開一個(gè)socket監(jiān)聽
socket_create_pair() 產(chǎn)生一對沒有區(qū)別的socket到一個(gè)數(shù)組里
socket_create() 產(chǎn)生一個(gè)socket,相當(dāng)于產(chǎn)生一個(gè)socket的數(shù)據(jù)結(jié)構(gòu)
socket_get_option() 獲取socket選項(xiàng)
socket_getpeername() 獲取遠(yuǎn)程類似主機(jī)的ip地址
socket_getsockname() 獲取本地socket的ip地址
socket_iovec_add() 添加一個(gè)新的向量到一個(gè)分散/聚合的數(shù)組
socket_iovec_alloc() 這個(gè)函數(shù)創(chuàng)建一個(gè)能夠發(fā)送接收讀寫的iovec數(shù)據(jù)結(jié)構(gòu)
socket_iovec_delete() 刪除一個(gè)已經(jīng)分配的iovec
socket_iovec_fetch() 返回指定的iovec資源的數(shù)據(jù)
socket_iovec_free() 釋放一個(gè)iovec資源
socket_iovec_set() 設(shè)置iovec的數(shù)據(jù)新值
socket_last_error() 獲取當(dāng)前socket的最后錯(cuò)誤代碼
socket_listen() 監(jiān)聽由指定socket的所有連接
socket_read() 讀取指定長度的數(shù)據(jù)
socket_readv() 讀取從分散/聚合數(shù)組過來的數(shù)據(jù)
socket_recv() 從socket里結(jié)束數(shù)據(jù)到緩存
socket_recvfrom() 接受數(shù)據(jù)從指定的socket,如果沒有指定則默認(rèn)當(dāng)前socket
socket_recvmsg() 從iovec里接受消息
socket_select() 多路選擇
socket_send() 這個(gè)函數(shù)發(fā)送數(shù)據(jù)到已連接的socket
socket_sendmsg() 發(fā)送消息到socket
socket_sendto() 發(fā)送消息到指定地址的socket
socket_set_block() 在socket里設(shè)置為塊模式
socket_set_nonblock() socket里設(shè)置為非塊模式
socket_set_option() 設(shè)置socket選項(xiàng)
socket_shutdown() 這個(gè)函數(shù)允許你關(guān)閉讀、寫、或者指定的socket
socket_strerror() 返回指定錯(cuò)誤號的詳細(xì)錯(cuò)誤
socket_write() 寫數(shù)據(jù)到socket緩存
socket_writev() 寫數(shù)據(jù)到分散/聚合數(shù)組

(注: 函數(shù)介紹刪減了部分原文內(nèi)容,函數(shù)詳細(xì)使用建議參考英文原文,或者參考php手冊)
以上所有的函數(shù)都是php中關(guān)于socket的,使用這些函數(shù),你必須把你的socket打開,如果你沒有打開,請編輯你的php.ini文件,去掉下面這行前面的注釋:
extension=php_sockets.dll
如果你無法去掉注釋,那么請使用下面的代碼來加載擴(kuò)展庫:
復(fù)制代碼 代碼如下:
<?php
if(!extension_loaded(‘sockets'))
{
if(strtoupper(substr(php_OS, 3)) == “WIN”)
{
dl(‘php_sockets.dll');
}
else
{
dl(‘sockets.so');
}
}
?>

如果你不知道你的socket是否打開,那么你可以使用phpinfo()函數(shù)來確定socket是否打開。你通過查看phpinfo信息了解socket是否打開。如下圖:
查看phpinfo()關(guān)于socket的信息

◆ 產(chǎn)生一個(gè)服務(wù)器
現(xiàn)在我們把第一個(gè)例子進(jìn)行完善。你需要監(jiān)聽一個(gè)指定的socket并且處理用戶的連接。
復(fù)制代碼 代碼如下:
<?php
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337);
socket_listen($socket);
// Accept any incoming connections to the server
$connection = socket_accept($socket);
if($connection)
{
socket_write($connection, "You have connected to the socket.../n/r");
}
?>

你應(yīng)該使用你的命令提示符來運(yùn)行這個(gè)例子。理由是因?yàn)檫@里將產(chǎn)生一個(gè)服務(wù)器,而不是一個(gè)Web頁面。如果你嘗試使用Web瀏覽器來運(yùn)行這個(gè)腳本,那么很有可能它會超過30秒的限時(shí)。你可以使用下面的代碼來設(shè)置一個(gè)無限的運(yùn)行時(shí)間,但是還是建議使用命令提示符來運(yùn)行。
set_time_limit(0);
在你的命令提示符中對這個(gè)腳本進(jìn)行簡單測試:
php.exe example01_server.php
如果你沒有在系統(tǒng)的環(huán)境變量中設(shè)置php解釋器的路徑,那么你將需要給php.exe指定詳細(xì)的路徑。當(dāng)你運(yùn)行這個(gè)服務(wù)器端的時(shí)候,你能夠通過遠(yuǎn)程登陸(telNET)的方式連接到端口1337來測試這個(gè)服務(wù)器。如下圖:

上面的服務(wù)器端有三個(gè)問題:
1. 它不能接受多個(gè)連接。
2. 它只完成唯一的一個(gè)命令。
3. 你不能通過Web瀏覽器連接這個(gè)服務(wù)器
這個(gè)第一個(gè)問題比較容易
解決,你可以使用一個(gè)應(yīng)用程序去每次都連接到服務(wù)器。但是后面的問題是你需要使用一個(gè)Web頁面去連接這個(gè)服務(wù)器,這個(gè)比較困難。你可以讓你的服務(wù)器接受連接,然后些數(shù)據(jù)到客戶端(如果它一定要寫的話),關(guān)閉連接并且等待下一個(gè)連接。
在上一個(gè)代碼的基礎(chǔ)上再改進(jìn),產(chǎn)生下面的代碼來做你的新服務(wù)器端:
復(fù)制代碼 代碼如下:
<?php
// Set up our socket
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, 'localhost', 1337);
socket_listen($socket);
// Initialize the buffer
$buffer = "NO DATA";
while(true)
{
// Accept any connections coming in on this socket

$connection = socket_accept($socket);
printf("Socket connected/r/n");
// Check to see if there is anything in the buffer
if($buffer != "")
{
printf("Something is in the buffer...sending data.../r/n");
socket_write($connection, $buffer . "/r/n");
printf("Wrote to socket/r/n");
}
else
{
printf("No Data in the buffer/r/n");
}
// Get the input
while($data = socket_read($connection, 1024, php_NORMAL_READ))
{
$buffer = $data;
socket_write($connection, "Information Received/r/n");
printf("Buffer: " . $buffer . "/r/n");
}
socket_close($connection);
printf("Closed the socket/r/n/r/n");
}
?>

這個(gè)服務(wù)器端要做什么呢?它初始化一個(gè)socket并且打開一個(gè)緩存收發(fā)數(shù)據(jù)。它等待連接,一旦產(chǎn)生一個(gè)連接,它將打印“Socket connected”在服務(wù)器端的屏幕上。這個(gè)服務(wù)器檢查緩沖區(qū),如果緩沖區(qū)里有數(shù)據(jù),它將把數(shù)據(jù)發(fā)送到連接過來的計(jì)算機(jī)。然后它發(fā)送這個(gè)數(shù)據(jù)的接受信息,一旦它接受了信息,就把信息保存到數(shù)據(jù)里,并且讓連接的計(jì)算機(jī)知道這些信息,最后關(guān)閉連接。當(dāng)連接關(guān)閉后,服務(wù)器又開始處理下一次連接。(翻譯的爛,附上原文)
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.

◆ 產(chǎn)生一個(gè)客戶端
處理第二個(gè)問題是很容易的。你需要產(chǎn)生一個(gè)php頁連接一個(gè)socket,發(fā)送一些數(shù)據(jù)進(jìn)它的緩存并處理它。然后你又個(gè)處理后的數(shù)據(jù)在還頓,你能夠發(fā)送你的數(shù)據(jù)到服務(wù)器。在另外一臺客戶端連接,它將處理那些數(shù)據(jù)。
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.

下面的例子示范了使用socket:
復(fù)制代碼 代碼如下:
<?php
// Create the socket and connect
$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 == “NO DATA”)
{
echo(“<p>NO DATA</p>”);
break;
}
else
{
// Do something with the data in the buffer
echo(“<p>Buffer Data: “ . $buffer . “</p>”);
}
}
echo(“<p>Writing to Socket</p>”);
// Write some test data to our socket
if(!socket_write($socket, “SOME DATA/r/n”))
{
echo(“<p>Write failed</p>”);
}
// Read any response from the socket
while($buffer = socket_read($socket, 1024, php_NORMAL_READ))
{
echo(“<p>Data sent was: SOME DATA<br> Response was:” . $buffer . “</p>”);
}
echo(“<p>Done Reading from Socket</p>”);
?>

這個(gè)例子的代碼演示了客戶端連接到服務(wù)器。客戶端讀取數(shù)據(jù)。如果這是第一時(shí)間到達(dá)這個(gè)循環(huán)的首次連接,這個(gè)服務(wù)器將發(fā)送“NO DATA”返回給客戶端。如果情況發(fā)生了,這個(gè)客戶端在連接之上。客戶端發(fā)送它的數(shù)據(jù)到服務(wù)器,數(shù)據(jù)發(fā)送給服務(wù)器,客戶端等待響應(yīng)。一旦接受到響應(yīng),那么它將把響應(yīng)寫到屏幕上。

php技術(shù)深入php socket的講解與實(shí)例分析,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 国产亚洲精品久久久久5区 国产亚洲精品久久久久 | gay吊粗大双龙 | 精品国产乱码久久久久久软件 | 色偷偷影院 | 精品视频在线观看视频免费视频 | 中文字幕亚洲综合小综合在线 | 偷窥 亚洲 色 国产 日韩 | 免费夜里18款禁用软粉色 | 日日a.v拍夜夜添久久免费 | 精品免费久久久久久成人影院 | 热久久2018亚洲欧美 | 亚洲片在线观看 | 女人的选择hd | 纵欲(高H) | 午夜伦理伦理片在线观 | 欧美GAY猛男GAYA片18禁 | 精品国产福利在线视频 | 超碰99热在线精品视频 | 琪琪婷婷五月色综合久久 | 国产 亚洲 日韩 欧美 在线观看 | 国产色偷偷男人的天堂 | 亚洲AV无码国产精品午夜久久 | 国产69精品久久久久乱码免费 | 国产精品福利片 | 亚洲高清视频免费 | 国产精品av | 天天久久影视色香综合网 | 人妻无码AV中文系统久久免费 | 影音先锋亚洲AV少妇熟女 | 无限资源在线观看高清 | 国产在线成人一区二区三区 | 果冻传媒视频在线播放 免费观看 | 1级午夜影院费免区 | 99影视久久电影网久久看影院 | 久99re视频9在线观看 | 国产日韩亚洲精品视频 | 亚洲精品久久一区二区三区四区 | 好紧好湿太硬了我太爽了小说 | 国产精品18久久久久久白浆. | 伊人久久免费 | TIMI1TV天美传媒在线观看 |