零.序言
经过上面一系列的学习,我们已经学会了gatewaywork的基本使用,下面让我们来动手将我们这个即时通信的项目的骨架搭建起来吧
一.数据结构的定义
在上面我们已经说了,客户端与服务的数据交互,只能是字符串,
为了方便我们将那些字符串格式化为json
在这个项目内,我们会进行非常多的数据交互,那么为了我们能在编码时的规范,我们将所有的交互的数据都定义为以下的数据结构
$data = [
"type" => "say_txt",//传递的类型
"from_uid" => 10,//发送者的uid
"to_uid" => 20,//接收者的uid
"data" => "我是10,你好啊20"//想要传递的数据
];
然后每次发送我们都将按着这个结构去生成对应的数据,然后格式化为json,进行数据交互
二.服务器的架构
因为这个项目的原理是这样
客户端所有的接受,发送等操作,都不是直接给他想要发送的那个客户端,
而是先发送给服务器,服务器进行相应的操作以后,再有服务器发送给想要发送的那个客户端,
例如A向B发送一个hellow world
不能直接A把数据给B
而是应该,A把数据先给服务器
服务器进行相关的操作
服务器再把数据传给B
所以服务器的onmessage方法(服务器接受到客户端传来消息时触发)会相当使用的相当频繁
下面就让我们具体看看onmessage函数的通用逻辑模板应该怎么编写吧
最开始它长这样
/**
* 当客户端发来消息时触发
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
//code...
}
然后我们知道$message参数就是客户端传来的信息是json格式,
所以我们不能直接拿来用,
我们先把jons格式解码为php里的对象进行操作
/**
* 当客户端发来消息时触发
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
//获取客户端发送的json
$client_obj = json_decode($message);
//code...
}
举个栗子,现在客户端发送过来一个要求将一段文字发送给另一个客户端的请求
首先客户端发来的json会是这样的格式
$data = [
"type" => "say_txt", //传递的类型
"from_uid" => 10, //发送者的uid
"to_uid" => 20, //接收者的uid
"data" => "我是10,你好啊20" //想要传递的数据
];
那我们应该先分析,客户端传来的这个数据,他想进行什么操作,是给某人发消息,还是询问某人是否在线等
我们首先应该根据数据中的type选择对应的操作
/**
* 当客户端发来消息时触发
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
//获取客户端发送的json
$client_obj = json_decode($message);
//判断用户发送的信息的类型
switch ($client_obj->type){
//发送给某个人文字
case "say_txt":
//code..........
break;
}
}
然后再再对应具体的逻辑进行编写
public static function onMessage($client_id, $message)
{
//获取客户端发送的json
$client_obj = json_decode($message);
//code...
//判断用户发送的信息的类型
switch ($client_obj->type){
//发送给某个人文字
case "say_txt":
//向接收者推送消息
$data = [
"type" => 'say_txt',
"from_uid" => $client_obj->from_uid,
"to_uid" => $client_obj->to_uid,
"data" => $client_obj->data,
];
Gateway::sendToUid($client_obj->to_uid,json_encode($data));
break;
}
}
那比如我们现在要写a询问b是否在线的请求怎么写呢
1.在case里新增一个is_online的分支
2.在is_online里去编写具体的逻辑
public static function onMessage($client_id, $message)
{
//获取客户端发送的json
$client_obj = json_decode($message);
//code...
//判断用户发送的信息的类型
switch ($client_obj->type){
//发送给某个人文字
case "say_txt":
//向接收者推送消息
$data = [
"type" => 'say_txt',
"from_uid" => $client_obj->from_uid,
"to_uid" => $client_obj->to_uid,
"data" => $client_obj->data,
];
Gateway::sendToUid($client_obj->to_uid,json_encode($data));
break;
//判断某个用户是否在线
case "is_online":
$status = Gateway::isUidOnline($client_obj->to_uid);
$data = [
"type" => "is_online",
"status" => $status,
];
//向发送者返回接受者是否在线的消息
Gateway::sendToUid($client_obj->from_uid,json_encode($data));
break;
}
}
所以以后所有的逻辑都可以按照上面的模板进行编写
三.客户端的架构
客户端的架构与服务器基本一致
只不过客户端收到服务器传来的信息时,触发的是websocked对象的onmessage方法,话不多说,上代码
1.获取数据,并格式化为js对象
//检测服务器是否给客户端发送消息
ws.onmessage = function(e){
//获取服务器传来的数据
let server_data = JSON.parse(e.data);
}
2.根据服务器传来数据中类型的不同,创建不同的分支
//检测服务器是否给客户端发送消息
ws.onmessage = function(e){
//获取服务器传来的数据
let server_data = JSON.parse(e.data);
switch (server_data.type){
//收到服务器发来要求初始化的消息
case "init":
//code...
break;
}
}
3.编写具体的逻辑代码
//检测服务器是否给客户端发送消息
ws.onmessage = function(e){
//获取服务器传来的数据
let server_data = JSON.parse(e.data);
switch (server_data.type){
//收到服务器发来要求初始化的消息
case "init":
//绑定uid
init_information();
//获取用户名与头像
get_head_img();
//将所有的与接收者的消息该为以读
set_allRead();
break;
}
}
4.当有新功能需要添加时,重复2,3即可
//检测服务器是否给客户端发送消息
ws.onmessage = function(e){
//获取服务器传来的数据
let server_data = JSON.parse(e.data);
switch (server_data.type){
//收到服务器发来要求初始化的消息
case "init":
//绑定uid
init_information();
//获取用户名与头像
get_head_img();
//将所有的与接收者的消息该为以读
set_allRead();
break;
//判读某个用户是否在线
case "is_online":
is_online(server_data.status);
break;
}
}