PHP 下的 Socket 简单编程(一)

Socket 并不是一个协议, 其本质是对 TCP/IP 协议进行的封装, 并对外提供了一组接口, 允许用户可以自由的按相关协议组装数据, 与服务器进行交互. 一切基于 TCP/IP 的协议可以通过 Socket 进行实现.
PHP 通过 Socket 扩展也可以实现对 Socket 编程. 使用 PHP 进行 Socket 通信的简单过程如下:
Alt textAlt text
PHP Socket 编程涉及的主要函数:
socket_create(): 初始化一个socket资源
socket_bind(): 将socket资源绑定到指定地址
socket_listen(): 监听socket的连接请求
socket_accept(): 接受来自客户端的连接, 返回一个新socket资源用于通讯. 如果接收到多个连接, 只会使用第一个连接. 没有连接时, 该函数保持堵塞状态, 直到有新的连接. 如果使用socket_set_blocking() or socket_set_nonblock()将socket设置为非堵塞状态, 没有连接时该函数返回FALSE
socket_read(): 从连接资源中读取指定字节数的数据, 读取成功时, 返回字符串. 失败时, 返回FALSE. 没有数据时, 返回空字符串
socket_write(): 向连接资源写入信息返回给客户端
socket_strerror(): 根据错误号获取错误消息
socket_last_error(): 返回上一次错误的错误号

示例一: 客户端和服务端的一对一通信, 由客户端推送数据到服务端

client.php
$host = '127.0.0.1';
$port = 65533;
if(($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE)
{
exit('初始化socket资源错误: ' . socket_strerror(socket_last_error($sock)));
}
 
if(socket_connect($sock, $host, $port) === FALSE)
{
exit('连接socket失败: ' . socket_strerror(socket_last_error($sock)));
}
 
$msg = '客户端1消息';
if(socket_write($sock, $msg) === FALSE)
{
exit('发送数据失败: ' . socket_strerror(socket_last_error($sock)));
}
 
$data = '';
// 循环读取指定长度的服务器响应数据
while($response = socket_read($sock, 4))
{
$data .= $response;
}
echo $data . PHP_EOL;
 
socket_close($sock);

 

server.php
set_time_limit(0);
 
$ip = '127.0.0.1';
$port = '65533';
$count = 1;
// socket_create(): 初始化一个socket资源
// socket_strerror(): 根据错误号获取错误消息
// socket_last_error(): 返回上一次错误的错误号
if(($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE)
{
echo '初始化socket失败: ' . socket_strerror(socket_last_error($sock));
die;
}
 
// socket_bind(): 将socket资源绑定到指定地址
if(!socket_bind($sock, $ip, $port))
{
echo '绑定端口失败: ' . socket_strerror(socket_last_error($sock));
die;
}
 
// socket_listen(): 监听socket的连接请求
if(!socket_listen($sock))
{
echo '监听端口: ' . socket_strerror(socket_last_error($sock));
die;
}
 
while(1)
{
// socket_accept(): 接受来自客户端的连接, 返回一个新socket资源用于通讯. 如果接收到多个连接, 只会使用第一个连接. 没有连接时, 该函数保持堵塞状态, 直到有新的连接. 如果使用socket_set_blocking() or socket_set_nonblock()将socket设置为非堵塞状态, 没有连接时该函数返回FALSE
;
if(($client = socket_accept($sock)) === FALSE)
{
echo '接收连接失败: ' . socket_strerror(socket_last_error($sock));
die;
}
 
// socket_read(): 从连接资源中读取指定字节数的数据, 读取成功时, 返回字符串. 失败时, 返回FALSE. 没有数据时, 返回空字符串
$content = socket_read($client, 1024);
if($content !== FALSE)
{
echo '消息' . $count . ': ' . $content . PHP_EOL;
$count++;
$response = '接收信息成功!';
// socket_write(): 向连接资源写入信息返回给客户端
socket_write($client, $response);
socket_close($client);
}else
{
exit('读取数据错误: ' . socket_strerror(socket_last_error($client)));
}
}
 
socket_close($sock);

 

首先在命令行下启动 server.php, 然后启动 client.php.
服务消息提示:
Alt text
客户端接收的响应消息提示
Alt text
客户端接收到服务端的响应消息后将断开连接, 而服务端会一直挂起, 等待下一次的连接.

示例二: 客户端和服务端的一对一通信, 由服务端推送数据到客户端

client.php
// 服务端地址
$host = '127.0.0.1';
$port = 65533;
if(($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE)
{
exit('初始化socket资源错误: ' . socket_strerror(socket_last_error($sock)));
}
 
if(socket_connect($sock, $host, $port) === FALSE)
{
exit('连接socket失败: ' . socket_strerror(socket_last_error($sock)));
}
 
$data = '';
// 循环读取指定长度的服务器响应数据
while($response = socket_read($sock, 4))
{
$data .= $response;
}
socket_write($sock, '接收消息成功');
echo $data . PHP_EOL;
 
socket_close($sock);

 

server.php
set_time_limit(0);
 
$ip = '127.0.0.1';
$port = '65533';
// socket_create(): 初始化一个socket资源
// socket_strerror(): 根据错误号获取错误消息
// socket_last_error(): 返回上一次错误的错误号
if(($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === FALSE)
{
echo '初始化socket失败: ' . socket_strerror(socket_last_error($sock));
die;
}
 
// socket_bind(): 将socket资源绑定到指定地址
if(!socket_bind($sock, $ip, $port))
{
echo '绑定端口失败: ' . socket_strerror(socket_last_error($sock));
die;
}
 
// socket_listen(): 监听socket的连接请求
if(!socket_listen($sock))
{
echo '监听端口: ' . socket_strerror(socket_last_error($sock));
die;
}
 
// 建立死循环,循环接收客户端的连接请求,持续向连接上的客户端推送消息
while(1)
{
// socket_accept(): 接受来自客户端的连接, 返回一个新socket资源用于通讯. 如果接收到多个连接, 只会使用第一个连接. 没有连接时, 该函数保持堵塞状态, 直到有新的连接. 如果使用socket_set_blocking() or socket_set_nonblock()将socket设置为非堵塞状态, 没有连接时该函数返回FALSE
;
if(($client = socket_accept($sock)) === FALSE)
{
echo '接收连接失败: ' . socket_strerror(socket_last_error($sock));
die;
}
$data = '服务端消息: ' . date('Y-m-d H:i:s', time());
socket_write($client, $data);
socket_close($client);
}
 
socket_close($sock);

 

首先通过命令行启动 server.php, 此时服务端将挂起, 持续监听指定端口. 然后启动 client.php, 客户端发起连接, 连接成功后, 将接收到服务端推送的数据.
客户单响应提示:
Alt text
posted @ 2019-07-27 11:46  有风来  阅读(326)  评论(0编辑  收藏  举报