编程学习网 > PHP技术 > php高级 > PHP 下的 Socket 编程
2020
04-29

PHP 下的 Socket 编程



Socket 并不是一个协议, 其本质是对 TCP/IP 协议进行的封装, 并对外提供了一组接口, 允许用户可以自由的按相关协议组装数据, 与服务器进行交互。

一切基于 TCP/IP 的协议可以通过 Socket 进行实现。


PHP 通过 Socket 扩展也可以实现对 Socket 编程,使用 PHP 进行 Socket 通信的简单过程如下:

v2-417cd7a9a13cf786ba17c24d46492965_720w.jpg

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,

服务消息提示:

v2-888ffbdf870adb6d326d5f33e0bc5e97_720w.jpg


客户端接收的响应消息提示

v2-0a2a8f7005ef6f120f5875ecd01baa9f_720w.jpg

客户端接收到服务端的响应消息后将断开连接, 而服务端会一直挂起, 等待下一次的连接.


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

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, 客户端发起连接, 连接成功后, 将接收到服务端推送的数据。


客户单响应提示:

v2-9f35c9f7c18ca96ef45c659ea003f33b_720w.jpg




扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取