IM-DEMO
即时通讯demo;主要功能:登录、注册、发送消息、添加好友、离线消息
环境
Ubuntu 16.04
Redis 4.0.8
Laravel 5.6
Swoole 2.1.0
Beanstalkd 1.1.0
MySQL 5.7.21
目录结构
im-demo : 前台页面
im-demo/js/config.js
//laravel-server地址
var api_host = 'http://localhost:8001';
//websocket服务地址
var websocket_host = 'ws://localhost:1024';
laravel-server : 主要提供接口,nginx配置根目录为public
swoole-server : websocket服务,用于转发消息
swoole-server/server.php
//启动websocket服务,监听所有地址的1024端口
$server = new swoole_websocket_server("0.0.0.0", 1024);
//连接redis服务
$redis->connect('127.0.0.1', 6379);
安装配置
1.配置laravel-server/public为nginx的根目录,并将config.js中的api_host修改为当前地址
2.在laravel-server目录下执行数据迁移语句
php artisan migrate
3.启动队列消费进程
php artisan queue:work
4.切换到swoole-server目录,启动websocket服务,并修改config.js中的websocket_host为服务地址
php server.php start
逻辑
登录:im-demo登录成功后连接websocket服务器时,会返回消息类型为login的消息,
内容包括client_id,再将client_id与token发送到laravel-server绑定.
发送消息:im-demo发送消息到laravel-server,laravel-server处理逻辑与验证,
后将消息加入队列中.
消息队列:当im-demo请求laravel-server时,laravel-server并没有直接将消息转发,而是将消息加入到beanstalkd队列中,另有进程处理这些消息.
laravel-server/app/Jobs/sendMessage.php
public function __construct(Users $from_user, Users $to_user, Messages $message)
{
$this->message = $message;
$this->to_user = $to_user;
$this->from_user = $from_user;
$this->client = new Client('ws://127.0.0.1:1024');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try{
$this->client->send(json_encode([
'type'=>'send_to_friend',
'friend_id'=>$this->to_user->id,
'msg'=>$this->message->content,
'from'=>$this->from_user->user_name
]));
$this->client->close();
$this->message->status = '1';
$this->message->save();
} catch (\Exception $exception)
{
}
}
离线消息:每次用户登录,都会查询是有未发送的消息,如果有则会加入队列中.
laravel-server/app/Jobs/sendOfflineMessage.php
public function __construct($user_id)
{
$this->user_id = $user_id;
$this->client = new Client('ws://127.0.0.1:1024');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try{
$message = new Messages();
$user = new Users();
$msg_list = $message->where(['to'=>$this->user_id,'status'=>'0'])->get();
foreach ($msg_list as $k=>$v) {
$this->client->send(json_encode([
'type'=>'send_to_friend',
'friend_id'=>$v->to,
'msg'=>$v->content,
'from'=>$user->find($v->from)->value('user_name')
]));
$v->status = '1';
$v->save();
}
$this->client->close();
} catch (\Exception $exception)
{
}
}
接收消息:当swoole-server接收到类型sent_to_frined的消息时,从redis中获取接收用户的client_id,并将消息发送到该client_id.