注意点:
- 如果网站使用HTTPS,WebSocket必须要使用wss协议
- 使用wss协议的连接请求必须只能写域名,而非IP+端口
- 通过nginx转发实现wss,内部通信就不需要使用wss了
Nginx 配置
- 只需要在HTTPS配置的server内加一个location即可
- Nginx反向代理,无论是HTTP/S或是WebSocket都会走443端口,由Nginx分发给各个项目服务器
location = /websocket {
proxy_pass http://xxxx.cn:7303
proxy_redirect off
proxy_set_header Host www.xxx.cn:7303
proxy_http_version 1.1
proxy_set_header Upgrade $http_upgrade
proxy_set_header Connection "upgrade"
}
Laravel
Server
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class WebSocket extends Command
{
protected $signature = 'Web {action=start}';
protected $description = 'WebSocket description';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$arg = $this->argument('action');
switch ($arg) {
case 'start':
$this->info('WebSocket observer started');
$this->start();
break;
}
}
public function start()
{
$server = new \swoole_websocket_server("0.0.0.0", 7303);
$server->set([
//后台作为守护进程运行 'daemonize' => 1
'daemonize' => 1,
//配置SSL证书和密钥路径
//'ssl_cert_file' => "/data/php/cert/www.xxxxx.cn.pem",
//'ssl_key_file' => "/data/php/cert/www.xxxxx.cn.key"
]);
$server->on('Open', array($this, 'OnOpen'));
$server->on('Message', array($this, 'OnMessage'));
$server->on('Close', array($this, 'OnClose'));
$server->start();
}
public function OnOpen($server, $req)
{
echo "server: handshake success with fd {$req->fd}\n";
}
public function OnMessage($server, $frame)
{
var_dump($frame);
$this->send($server, $frame);
}
public function OnClose($server, $fd)
{
echo "client {$fd} closed \n";
}
public function send($server, $frame)
{
$info = json_decode($frame->data, true);
switch ($info['action']) {
case 'home':
case 'device':
case 'goodsError':
case 'shopping':
$conn_list = $server->connection_list(0, 100);
if ($conn_list === false or count($conn_list) === 0) {
echo "finish \n";
}
foreach ($conn_list as $fd) {
if ($fd != $frame->fd) {
$arr = array("action" => $info['action'], "data" => $info['data']);
$data = json_encode($arr);
$server->push($fd, $data);
}
}
break;
}
}
}
Client
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class WebClient extends Command
{
protected $signature = 'SendSocket {data}';
protected $description = 'WebClient description';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$data = $this->argument('data');
$cli = new \swoole_http_client('127.0.0.1', 7303);
$cli->setHeaders(['Trace-Id' => md5(time()),]);
$cli->on('message', function ($_cli, $frame) {
var_dump($frame);
});
$cli->upgrade('/', function ($cli) use ($cli, $data) {
$cli->push($data);
$cli->close();
});
}
}
WEB
# 地址后面必须加 /websocket
let ws = new WebSocket("wss://www.xxx.com:7300/websocket');
ws.onopen = function(evt) {
console.log("Connection open ...");
};
ws.onmessage = function (evt) {
let hashValue = window.location.hash.split('/');
let hashLength = hashValue . length;
let newKey = hashValue[hashLength - 1];
console . log("Received Message: " + evt . data);
let data = JSON . parse(evt . data);
if (data.action === 'home' && newKey === '') {
console . log('home-socket');
$this.homeSocket();
} else if (data.action === 'home' && newKey === 'shoppingMonitor') {
console.log('shopping-home-socket')
$this.shoppingMonitorSocket();
} else if (data . action === 'shopping' && newKey === 'shoppingMonitor') {
console.log('shopping-socket');
$this . shoppingMonitorSocket();
} else if (data . action === 'goodsError') {
console.log('goodsError-socket');
}
}
ws.onclose = function(e){
console.log("close");
}
ws.onerror = function(e){
console.log(error);
}