對(duì)于Socket編程首先需要先了解以下幾個(gè)知識(shí)點(diǎn):
1定页、什么是TCP/IP蜈抓、UDP驯妄、Http能耻、Socket帆竹?
TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協(xié)議/網(wǎng)間協(xié)議绕娘,是一個(gè)工業(yè)標(biāo)準(zhǔn)的協(xié)議集,它是為廣域網(wǎng)(WANs)設(shè)計(jì)的栽连。
UDP(User Data Protocol险领,用戶數(shù)據(jù)報(bào)協(xié)議)是與TCP相對(duì)應(yīng)的協(xié)議。它是屬于TCP/IP協(xié)議族中的一種秒紧。
HTTP 協(xié)議即超文本傳送協(xié)議(Hypertext Transfer Protocol )绢陌,是Web聯(lián)網(wǎng)的基礎(chǔ),也是手機(jī)聯(lián)網(wǎng)常用的協(xié)議之一熔恢,HTTP協(xié)議是建立在TCP協(xié)議之上的一種應(yīng)用脐湾。
Socket 是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議叙淌,而是一個(gè)調(diào)用接口(API)沥割,通過(guò)Socket耗啦,我們才能使用TCP/IP協(xié)議。
Ps:
簡(jiǎn)單理解http是短鏈机杜,tcp是長(zhǎng)鏈帜讲,
短鏈?zhǔn)侨シ?wù)器拉數(shù)據(jù),長(zhǎng)鏈?zhǔn)欠?wù)器可以主動(dòng)推數(shù)據(jù)椒拗。
2似将、Socket是什么呢?
Socket就是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層蚀苛,它是一組接口在验。在設(shè)計(jì)模式中,Socket其實(shí)就是一個(gè)門面模式堵未,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面腋舌,對(duì)用戶來(lái)說(shuō),一組簡(jiǎn)單的接口就是全部渗蟹,讓Socket去組織數(shù)據(jù)块饺,以符合指定的協(xié)議。
PHP中的Socket
Socket擴(kuò)展是基于流行的BSD sockets雌芽,實(shí)現(xiàn)了和socket通訊功能的底層接口授艰,它可以和客戶端一樣當(dāng)做一個(gè)socket服務(wù)器。
Socket相關(guān)函數(shù)
socket_accept() 接收一個(gè)socket連接
socket_bind() 把socket綁定在一個(gè)IP地址和端口上
socket_clear_error() 清除socket的錯(cuò)誤或者最后的錯(cuò)誤代碼
socket_close() 關(guān)閉一個(gè)socket資源
socket_connect() 開(kāi)始一個(gè)socket連接
socket_create_listen() 在指定端口打開(kāi)一個(gè)socket監(jiān)聽(tīng)
socket_create_pair() 產(chǎn)生一對(duì)沒(méi)有區(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)聽(tīng)由指定socket的所有連接
socket_read() 讀取指定長(zhǎng)度的數(shù)據(jù)
socket_readv() 讀取從分散/聚合數(shù)組過(guò)來(lái)的數(shù)據(jù)
socket_recv() 從socket里結(jié)束數(shù)據(jù)到緩存
socket_recvfrom() 接受數(shù)據(jù)從指定的socket淮腾,如果沒(méi)有指定則默認(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ò)誤號(hào)的詳細(xì)錯(cuò)誤
socket_write() 寫數(shù)據(jù)到socket緩存
socket_writev() 寫數(shù)據(jù)到分散/聚合數(shù)組
Socket案例
server.php (服務(wù)器端)
<?php
/**
* Socket服務(wù)端
* author: flycorn
* email: ym1992it@163.com
* time: 16/12/27 下午3:43
*/
//設(shè)置無(wú)限請(qǐng)求超時(shí)時(shí)間
set_time_limit(0);
$ip = '127.0.0.1';
$port = 8099;
//創(chuàng)建socket
if(($sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {
echo "socket_create() 失敗的原因是:".socket_strerror($sock)."\n";
exit();
}
//把socket綁定在一個(gè)IP地址和端口上
if(($ret = socket_bind($sock,$ip,$port)) < 0) {
echo "socket_bind() 失敗的原因是:".socket_strerror($ret)."\n";
exit();
}
//監(jiān)聽(tīng)由指定socket的所有連接
if(($ret = socket_listen($sock,4)) < 0) {
echo "socket_listen() 失敗的原因是:".socket_strerror($ret)."\n";
exit();
}
//次數(shù)
$count = 0;
do{
//接收一個(gè)Socket連接
if (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
break;
} else {
//發(fā)送到客戶端
$msg = "測(cè)試成功! \n";
socket_write($msgsock, $msg, strlen($msg));
echo "測(cè)試成功了啊\n";
// 獲得客戶端的輸入
$buf = socket_read($msgsock, 2048);
$talkback = "收到的信息:$buf\n";
echo $talkback;
//第5次結(jié)束
if(++$count >= 5){
break;
}
}
//關(guān)閉socket
socket_close($msgsock);
}while(true);
client.php (客戶端)
<?php
/**
* Socket客戶端
* author: flycorn
* email: ym1992it@163.com
* time: 16/12/27 下午4:03
*/
error_reporting(E_ALL);
//設(shè)置無(wú)限請(qǐng)求超時(shí)時(shí)間
set_time_limit(0);
echo "<h2>TCP/IP Connection</h2>\n";
$ip = '127.0.0.1';
$port = 8099;
//創(chuàng)建socket
if(($socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0) {
echo "socket_create() 失敗的原因是:".socket_strerror($socket)."\n";
exit();
}
echo "OK. \n";
echo "試圖連接 '$ip' 端口 '$port'...\n";
//連接socket
if(($result = socket_connect($socket, $ip, $port)) < 0){
echo "socket_connect() 失敗的原因是:".socket_strerror($sock)."\n";
exit();
}
echo "連接OK\n";
$in .= "hello flycorn\r\n";
$out = '';
//寫數(shù)據(jù)到socket緩存
if(!socket_write($socket, $in, strlen($in))) {
echo "socket_write() 失敗的原因是:".socket_strerror($sock)."\n";
exit();
}
echo "發(fā)送到服務(wù)器信息成功谷朝!\n";
echo "發(fā)送的內(nèi)容為:$in \n";
//讀取指定長(zhǎng)度的數(shù)據(jù)
while($out = socket_read($socket, 2048)) {
echo "接收服務(wù)器回傳信息成功!\n";
echo "接收的內(nèi)容為:",$out;
}
echo "關(guān)閉SOCKET...\n";
socket_close($socket);
echo "關(guān)閉OK\n";
cli模式運(yùn)行:
1武花、打開(kāi)終端:php server.php
2徘禁、新開(kāi)一個(gè)終端:php client.php
3、服務(wù)端髓堪、客戶端分別會(huì)出現(xiàn)以下反饋: