這些Socket函數直接跟互聯網的協議進行發送信息。相對於fopensock的流來講,他們操作在一個比較底層的級別。通常,他們都是對C 函數進行封裝,並且名稱都類似。如果你有使用C進行socket編程的經驗,那麼使用這些函數將是非常熟練的。我們這裡不討論特別詳細的socket編程。
使用這些函數能夠解決高層級別函數所不能解決的難題。使用這些函數能夠實現類似fopen的功能,你也許有很多方法來實現socket的功能,比如在PHP中使用CLI(Command-line Interface)來實現的Internet守護進程。
resource socket_accept(resource socket)
在你的腳本服務器端中,使用socket_accept接受一個進入的連接。你必須首先產生一個socket,綁定它到一個名字,並且設置它監聽一個端口。在塊模式中,socket_accept將產生一個唯一接受後的連接。在非塊模式中,它沒有建立連接則返回false。另外,當你有了一個新的socket資源後就能夠進行讀寫操作。
下面我們將示范一個簡單的回顯服務器端。它運行在CLI(命令行)下面,它在12345端口等待客戶端的連接。
socket_accept
<?php
set_time_limit(0);
//create the socket
if(($socket = socket_create(AF_INET, SOCK_STREAM, 0)) < 0){
print("Couldnt create socket: " . socket_strerror(socket_last_error()) . "
");
}
//bind it to the given address and port
if(($error = socket_bind($socket, gethostbyname($_SERVER[HOSTNAME]), 12345)) < 0){
print("Couldnt bind socket: " . socket_strerror(socket_last_error()) . "
");
}
if(($error = socket_listen($socket, 5)) < 0){
print("Couldnt list on socket: " .
socket_strerror(socket_last_error()) . "
");
}
while(TRUE){
//wait for connection
if(($accept = socket_accept($socket)) < 0){
print("Error while reading: " . socket_strerror($message) . "
");
break;
}
//send welcome message
socket_write($accept, "Connection accepted
");
print(date(Y-m-d H:i:s) . " STATUS: Connection accepted
");
ob_flush();
while(TRUE){
//read line from client
if(FALSE === ($line = socket_read($accept, 1024))){
print("Couldnt read from socket: " .
socket_strerror(socket_last_error()) . "
");
break 2;
}
if(!@socket_write($accept, "ECHO: $line")){
print(date(Y-m-d H:i:s) . " STATUS: Connection interrupted
");
break;
}
print(date(Y-m-d H:i:s) . " READ: $line");
ob_flush();
}
socket_close($accept);
}
?>
bool socket_bind(resource socket, string address, integer port)
這個socket_bind()把一個socket資源綁定在一個地址上。這個socket必須由socket_create()函數返回的一個資源。這個地址必須是一個IP地址或者是一個保存Unix socket的路徑。如果是運行在Internet上的socket,你還必須提供一個端口。
socket_clear_error(resource socket)
這個函數能夠清除制定socket的錯誤,如果沒有指定參數,那麼將清除所有socket的錯誤。
socket_close(resource socket)
socket_close函數關閉一個socket並且清除該socket所占用的內存資源。
boolean socket_connect(resource socket, string address, integer port)
這個函數創建一個客戶端到一個端口或者socket的連接。你必須提供一個由socket_create產生的socket。這個address參數必須到一個socket的路徑或者是一個IP地址。如果是後者,還必須跟一個數字的端口號。
下面例子演示了使用UDP協議的連接到游戲服務器然後獲取信息的過程。
socket_connect
<?php
//create UDP socket
if(($socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) < 0){
print("Couldnt create socket: " .
socket_strerror(socket_last_error()) . "
");
}
//timeout after 5 seconds
socket_set_option($socket, SOL_SOCKET,
SO_RCVTIMEO, array(sec=>5,usec=>0));
//connect to the RtCW master server
if(!socket_connect($socket, wolfmaster.idsoftware.com, 27950)){
print("Couldnt connect: " .
socket_strerror(socket_last_error()) . "
");
}
//send request for servers
socket_write($socket, "xFFxFFxFFxFFgetserversx00");
//get servers
$server = array();
while(FALSE !== ($line = @socket_read($socket, 4096))){
//parse data
for($i=22; ($i+5) < strlen($line); $i += 7){
$ip = ord(substr($line, $i+1, 1)) . . .
ord(substr($line, $i+2, 1)) . . .
ord(substr($line, $i+3, 1)) . . .
ord(substr($line, $i+4, 1));
$port = (ord(substr($line, $i+5, 1)) * 256) +
ord(substr($line, $i+6, 1));
$server[] = array(ip=>$ip, port=>$port);
}
}
print("<h1>" . count($server) . " Servers</h1>
");
//loop over servers, getting status
foreach($server as $s){
&nb