服务器代码
<?php
use Swoole\WebSocket\Server;
class Test
{
public $ws;
public $redis;
public function __construct()
{
Co::set(['enable_preemptive_scheduler' => 0]);
$this->ws = new Server('0.0.0.0', 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);
$Config = [
'open_http_protocol' => true,
];
$this->ws->set($Config);
$this->ws->on('open', [$this, 'onOpen']);
$this->ws->on('message', [$this, 'onMessage']);
$this->ws->on('WorkerStart', [$this, 'onWorkerStart']);
$this->ws->on('request', [$this, 'onRequest']);
$this->ws->on('close', [$this, 'onClose']);
$serv = $this->ws->addlistener('0.0.0.0', 9503, SWOOLE_SOCK_TCP);
$serv->set([]);
$serv->on('receive', [$this, 'onReceive']);
}
public function onWorkerStart()
{
$this->redis = new Swoole\Coroutine\Redis();
$this->redis->connect('127.0.0.1', '6379');
$this->redis->auth('123456');
//清空绑定关系
$this->redis->del('user_fd');
$this->redis->del('device_user');
$this->redis->del('device_fd');
}
/**打开webscokt连接
* @param $ws
* @param $request
*/
public function onOpen($ws, $request)
{
$ws->push($request->fd, "hello, welcome\n");
}
/**websockt收到数据回调
* @param $ws
* @param $frame
* @return bool
*/
public function onMessage($ws, $frame)
{
$data = json_decode($frame->data, true);
$user_id = $data['user_id'] ?? null;
$device_id = $data['device_id'] ?? null;
if (!$user_id || !$device_id) {
$this->ws->push($frame->fd, "Parameter error");
return false;
}
$this->redis->hset('user_fd', $user_id, $frame->fd);
$this->redis->hset('device_user', $device_id, $user_id);
$this->ws->push($frame->fd, "server: {$frame->data}");
}
public function onClose($ws, $fd)
{
echo "client-{$fd} is closed\n";
}
/**http请求回调
* @param $request
* @param $response
*/
public function onRequest($request, $response)
{
$post_data = $request->post;
$device_cmd = $post_data['cmd'] ?? null;
$device_id = $post_data['device_id'] ?? null;
$device_fd = $this->redis->hget('device_fd', $device_id);
$user_id = $this->redis->hget('device_user', $device_id);
$user_fd = $this->redis->hget('user_fd', $user_id);
if ($user_fd) $this->ws->push($user_fd, $device_cmd);
//发送数据到tcp服务
if ($device_fd) {
$client = new \Swoole\Coroutine\Client(SWOOLE_SOCK_TCP);
$client->set(['max_coroutine' => 5,]);
if (!$client->connect('127.0.0.1', 9503, 0.5)) {
exit("connect failed. Error: {$client->errCode}\n");
}
$str = json_encode(['device_fd' => $device_fd, 'device_cmd' => $device_cmd]);
$client->send($str . "\r\n");
// echo $client->recv();
$client->close();
}
$response->header("Content-Type", "text/html; charset=utf-8");
$response->end("<h1>OK. #" . rand(1000, 9999) . "</h1>");
}
/**tcp接收数据回调
* @param $serv
* @param $fd
* @param $threadId
* @param $data
*/
public function onReceive($serv, $fd, $threadId, $data)
{
$data = json_decode($data, true);
$device_id = $data['device_id'] ?? null;
$device_fd = $data['device_fd'] ?? null;
$device_cmd = $data['device_cmd'] ?? null;
//绑定设备关系
if ($device_id) $this->redis->hset('device_fd', $device_id, $fd);
//发送到设备数据
if ($device_fd) $serv->send($device_fd, $device_cmd);
}
public function start()
{
$this->ws->start();
}
}
$model = new Test();
$model->start();
web前端代码
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
<script type="text/javascript">
// 打开一个 web socket
var ws = new WebSocket("ws://127.0.0.1:9501");
ws.onopen = function()
{
var str='{"user_id":1,"device_id":1}';
ws.send(str);
console.log('已链接');
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
console.log(evt.data);
};
ws.onclose = function()
{
// 关闭 websocket
console.log('已关闭');
};
</script>
</head>
<body>
</body>
</html>
测试,我们用tcp与WebSocket分别连接上服务器,然后通过http发送数据,然后在tcp与WebSocket都能收到数据
postman发送数据
tcp端
WebSocket端