服务端安装
composer require workerman/workerman
客户端安装
composer require textalk/websocket
服务器端
ssl证书是按域名申请的
<?php
namespace App\Controllers;
use Workerman\Worker;
use Workerman\Lib\Timer;
use WebSocket\Client;
class Workerman extends BaseController
{
protected $uidConnections = [];
protected $HEARTBEAT_TIME = '60';
public $code_arr = [
'100' => ['code'=>100, 'msg'=>'连接成功'],
'101' => ['code'=>101, 'msg'=>'登录成功'],
'102' => ['code'=>102, 'msg'=>'发送数据'],
'103' => ['code'=>103, 'msg'=>'接收成功'],
'131' => ['code'=>131, 'msg'=>'发送失败'],
];
protected $worker = null;
public $count = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'workerman:websocket';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
*
* @var string
*/
protected $redis = '';
/**
* SSL证书路径
* @var string
*/
protected $http_psth = '/usr/local/nginx/conf/cert/';
/**
* The console command description.
*
* @var string
*/
protected $redisname = 'long:';
/**
* Create a new command instance.
*
* @return void
*/
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->start();
}
public function start()
{
$context = array(
// 更多ssl选项请参考手册 http://php.net/manual/zh/context.ssl.php
'ssl' => array(
// 请使用绝对路径
'local_cert' => $this->http_psth.'域名.pem', // 也可以是crt文件
'local_pk' => $this->http_psth.'域名.key',
'verify_peer' => false,
'allow_self_signed' => true, //如果是自签名证书需要开启此选项
)
);
$this->worker = new Worker('websocket://0.0.0.0:1818', $context);
$this->worker->transport = 'ssl';
$this->onConnect();
$this->onMessage();
$this->onClose();
$this->redis = $this->redisdb();
Worker::runAll();
}
public function onConnect() {
$this->worker->onConnect = function($connection) {
$connection->send(json_encode($this->code_arr['100']));
$this->count++;
$msg = "新的连接 目前连接数 {$this->count}";
var_dump($msg);
log_message('error',$msg);
};
}
public function onMessage() {
$this->worker->onMessage = function ($connection, $data){
log_message('error','sssss:'.$data);
$connection->lastMessageTime = time(); //更新上一次会话时间
//客户端心跳 直接返回
if ($data == "") {
return;
}
$data = json_decode($data, true);
$uid = $uid = $data['uid'];
if (empty($uid)) {
$connection->close();
return;
}
log_message('error','uid:'.$uid);
switch ($data['type']) {
case 'login':
// 保存该用户的输送数据
$connection->uid = $uid;
$this->uidConnections[$uid] = $connection;
$msg = "uid:{$uid} 登录成功 目前登录数".count($this->uidConnections);
$send_data = $this->code_arr['101'];
// $send_data['info'] = $notify;
log_message('error',$msg);
$connection->send(json_encode($send_data));
break;
case 'send':
// 发送消息
$res = $this->sendMessageByUid($uid);
$msg = "发送成功";
if (!$res) {
$msg = "发送失败";
}
// var_dump($msg);
log_message('error',$msg);
break;
case 'message':
break;
}
};
}
// 针对uid推送数据
public function sendMessageByUid($uid)
{
if(isset($this->uidConnections[$uid]))
{
$notify = $this->redis->get($this->redisname.$uid);
if($notify){
$this->redis->delete($this->redisname.$uid);
$notify = unserialize($notify);
}
$send_data = $this->code_arr['102'];
$send_data['info'] = $notify;
$this->uidConnections[$uid]->send(json_encode($send_data));
return true;
}
return false;
}
public function onClose() {
$this->worker->onClose = function ($connection){
$this->count--;
if(isset($connection->uid)) {
$msg = "uid:{$connection->uid} 已断开";
var_dump($msg);
log_message('error',$msg);
unset($this->uidConnections[$connection->uid]);
}
$msg = "连接已断开 目前连接数 {$this->count}";
var_dump($msg);
log_message('error',$msg);
// Log::write("$msg", 'WorkerManServer');
};
}
public function redisdb($db=0)
{
$redis=new \redis();
$redis->connect(env("redis.default.host"),env("redis.default.port"));
$redis->select(env("redis.default.db"));
return $redis;
}
}
?>
服务器上的 客户端
public function test($data='')
{
$data = array(
'uid' => 1,
'type' => 'send',
'info' => ['sss1'=>11]
);
$json = json_encode($data);
$client = new Client("wss://域名:1818");
$client->send($json);
$data1 = array(
'uid' => 2,
'type' => 'send',
'info' => ['sss2'=>11]
);
$json = json_encode($data1);
$client->send($json);
$message = $client->receive();
log_message('error',$message);
$client->close();//WebSocket\
}
前端js代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="margin: 0 auto;width: 800px">
<h2>聊天室</h2>
<textarea type="text" style="border: 1px solid black;width: 800px;height: 200px;" id="his"></textarea>
<input type="text" style="width:740px" id="sendMsg"> <button id="send">发送</button>
</div>
</body>
</html>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function () {
var ws = new WebSocket("wss://域名:1818");
$('#send').click(function () {
msg = $('#sendMsg').val();
$('#sendMsg').val('');
ws.send(msg);
});
ws.onopen = function() {
$('#his').append("服务器连接成功.....");
$('#his').append("\n");
};
ws.onmessage = function(e) {
$('#his').append(e.data);
$('#his').append("\n");
};
});
</script>
参考无证书版本: