设计背景:
一台内网的TCP终端设备,需要将设备传输到外网的TcpServer服务器上,中间架设一台双网口的电脑,作为转发服务器
设计思路:
在中转服务器起一个tcpserver服务,当tcp终端连接的时候,起一个tcp_client客户端连接到外网的tcpserver服务器。
代码如下:
<?php
//error_reporting(0);
use Swoole\Coroutine\Client;
use Swoole\Coroutine\Channel;
use Swoole\Coroutine;
use function Swoole\Coroutine\run;
global $server;
$server = new \Swoole\Server('127.0.0.1', 9503);
$server->on('start', function ($server) {
echo "TCP Server is started at tcp://127.0.0.1:9503\n";
});
$server->on('connect', function ($server, $fd) {
echo date("Y-m-d H:i:s") . ":" . "钻机接入:connection open: {$fd}\n";
#1、监听钻机连接,记录其fd为$fd 并将其global
#2、如果钻机接入,就开始请求连接服务器,记录其client为$tcp_client 并将其global
#3、如果收到钻机的消息,则转发给服务器,如果收到服务器的响应,则转发给钻机
global $zj_fd;
$zj_fd = $fd;
global $tcp_client;
$tcp_client = new Client(SWOOLE_SOCK_TCP);
if (!$tcp_client->connect('192.168.0.126', 24001)) {
$tcp_client->close();
dump("连接服务端失败,此时说明客户端连接上来了,但无法连接到服务端,请检查服务端是否正常运行");
//$server->close($fd);
}
#调用协程--接收来自服务端的消息,并将其转发给钻机
server_data();
});
$server->on('receive', function ($server, $fd, $reactor_id, $data) {
global $tcp_client;
if ($tcp_client->isConnected()) {
$tcp_client->send($data);
dump("收到钻机消息,并转发给服务器:" . bin2hex($data));
} else {
if (!$tcp_client->connect('192.168.0.126', 24001)) {
$tcp_client->close();
dump("服务器中转连接失败,此时说明客户端有数据上来,但是发不到服务端去了,请检查服务端是否正常运行");
//$server->close($fd);
}
}
});
$server->on('close', function ($server, $fd) {
dump("connection close: {$fd}\n");
global $tcp_client;
$tcp_client->close();
});
$server->start();
function server_data()
{
//开启通道
$channel = new Channel(1);
Coroutine::create(function () use ($channel) {
while (true) {
global $tcp_client;
if (!$tcp_client->isConnected()) {
if (!$tcp_client->connect('192.168.0.126', 24001)) {
$tcp_client->close();
dump("客户端与服务器的连接是断开状态,此处说明是服务端宕机了,连不上了,请联系服务端管理人员😱");
//$server->close($fd);
continue;
} else {
dump("服务器中转连接成功========😊");
}
}
if ($tcp_client->isConnected()) {
//var_dump("连接正常\r\n");
$server_data = $tcp_client->recv();
global $server;
global $zj_fd;
if (strlen($server_data) > 0) {
dump("收到服务器消息,并转发给钻机:" . bin2hex($server_data));
$server->send($zj_fd, $server_data);
} else {
if ($tcp_client->errCode !== SOCKET_ETIMEDOUT) {
$tcp_client->close();
dump("服务器中转连接失败444");
//$server->close($fd);
}
dump("与服务端的实际连接断开,每隔1秒检测重连一下");
Coroutine::sleep(1);
}
}
}
});
}
function dump($msg)
{
echo date("Y-m-d H:i:s") . ":" . $msg . PHP_EOL;
}