SimpleRpc-客户端与服务端工作模型探讨
前言
本篇文章讲述客户端与服务端的具体设计细节。有细心的小伙伴发现,客户端和服务端的工作方式不一样:服务端是多线程计算模型,利用工作线程完成数据的读取,而客户端是单线程(利用Reactor线程完成数据的读取)。这么做的原因有二:首先我们认为我们的使用RPC的初衷是由于CPU计算是瓶颈,不得已把计算放到多台机器上,所以服务端采用多线程计算模型;其次我们认为网络IO只要不是客户端故意阻塞,那么无论是请求数据还是响应数据只需要一次接收就可以收全,不会有线程长时间阻塞在网络上,所以客户端就使用反应器线程进行接收响应数据。
客户端同步和异步调用
SimpleRpc提供了同步调用和异步调用的方法,使用区别在于传递的参数不同,如下所示。
//异步请求
int async_request(Server &server, Request *request, Response *response, ResultHandler *handler);
//同步请求
int sync_request(Server &server, Request *request, Response *response);
那么SimpleRpc对于同步和异步调用是如何支持的呢?我们重新看一下DownstreamHandler对数据的处理方式:
void DownstreamHandler::handle_read(int fd) {
char head[];
Connection conn(fd);
conn.recv_n(head, );
int size = *((int *)head);
char *buf = new char[size];
conn.recv_n(buf, size);
close(fd);
printf("Downstream Handler close fd:%d\n", fd);
//下游响应
_response->deserialize(buf, size);
//如果有result_handler,则调用data_comeback钩子函数
if(_result_handler != NULL) {
_result_handler->data_comeback(); //对于同步调用,这个方法会唤醒客户端使其从wait中返回
}
delete[] buf;
//自杀
delete this;
}
result_handler的调用是关键,我们正是利用这一点做到同步调用和异步调用。ResultHandler的类UML如下:

DefaultResultHandler是SimpleRpc的默认结果处理方式,UserDefinedResultHandler由用户自己选择性的定义并实现。当客户端工作线程对服务端相应数据处理完毕后,调用ResultHandler的data_comeback方法执行这个钩子函数。
- 同步调用的实现:
int SimpleRpcClient::sync_request(Server &server, Request *request, Response *response) {
Mutex mutex;
Connection conn;
Condition cond(&mutex);
InetAddr addr(server.get_port_str(), server.get_ip_str());
Connector conntor(addr);
int ret = conntor.Connect(conn); //建立与服务端的连接
if(ret == -){
LOG("connect error\n");
return -;
}
int size = request->bytes(); //获取请求序列化后的字节数
char *buf = new char[size + ]; //用额外4字节存放数据长度,方便接收端校验
if(buf == NULL) {
LOG("request oom, request need %d bytes\n", size + );
conn.Close();
return -;
}
int payload = request->serialize(buf + , size); //序列化
memcpy(buf, &payload, sizeof(int));
ret = conn.send_n(buf, payload + ); //发送序列化数据
if(ret != ) {
LOG("connection send error\n");
return -;
}
DefaultResultHandler *handler = new DefaultResultHandler(&cond, &mutex);
DownstreamHandler *down_handler =
new DownstreamHandler(conn.sock(), response, Reactor::get_instance(), handler);
Reactor::get_instance()->regist(conn.sock(), down_handler); //注册到reactor中等待响应事件的通知
handler->finish(); //阻塞调用,直到cond得到唤醒通知
delete[] buf;
delete handler;
return ;
}
我们的DefautlResultHandler拥有系统等待条件(Condition),并且作为DownstreamHandler的成员之一。客户端发送请求数据后,构造DownstreamHandler并注册到reactor中,等待服务端响应事件的通知。干完以上的事情之后,客户端应用线程调用DefaultResultHandler的finish方法阻塞直到得到完成通知,这样达到了同步调用的效果。
- 异步调用的实现:
异步调用没有使用DefaultResultHandler作为参数传递给DownstreamHandler,而是把用户自定义的ResultHanlder传递进去,具体的控制流程(data_comeback函数)由用户自己定义。
int SimpleRpcClient::async_request(
Server &server, Request *request, Response *response, ResultHandler *handler) {
...
DownstreamHandler *down_handler =
new DownstreamHandler(conn.sock(), response, Reactor::get_instance(), handler);
Reactor::get_instance()->regist(conn.sock(), down_handler);
...
}
服务端工作线程计算模型
我们知道服务端使用多线程进行数据的处理,那么每个线程的工作内容是什么呢?
template<class REQUEST, class RESPONSE>
class Processor : public Worker<StreamEvent> {
public:
virtual int process(REQUEST &request, RESPONSE &response) = ; void run() {
while(true){
StreamEvent e = get_event(); //队列中获取待处理事件
char head[];
Connection conn(e.fd);
int payload = conn.recv_n(head, ); //接收数据长度
if(payload == -) {
close(e.fd);
printf("Error Processor close fd:%d\n", e.fd);
return;
} REQUEST request;
RESPONSE response; int size = *((int *)head);
char *recv_buf = new char[size];
conn.recv_n(recv_buf, size); //接收请求数据
request.deserialize(recv_buf, size); //反序列化 process(request, response); //进行用户代码逻辑计算,由用户实现
size = response.bytes();
char *send_buf = new char[size + ];
memcpy(send_buf, &size, sizeof(int));
payload = response.serialize(send_buf + , size); //序列化响应数据
conn.send_n(send_buf, size + ); //发送响应数据
//为了正常关闭该链接,需要重新注册回reactor
UpstreamHandler *upHandler = new UpstreamHandler(e.fd, Reactor::get_instance());
Reactor::get_instance()->regist(e.fd, upHandler);
delete recv_buf;
delete send_buf;
}
}
virutal ~Processor(){}
}
SimpleRpc-客户端与服务端工作模型探讨的更多相关文章
- Asp.Net MVC 模型验证详解-实现客户端、服务端双重验证
概要 在asp.net webform开发中经常会对用户提交输入的信息进行校验,一般为了安全起见大家都会在客户端进行Javascript(利于交互).服务端双重校验(安全).书写校验代码是一个繁琐的过 ...
- NIO【同步非阻塞io模型】关于 NIO socket 的详细总结【Java客户端+Java服务端 + 业务层】【可以客户端间发消息】
1.前言 以前使用 websocket来实现双向通信,如今深入了解了 NIO 同步非阻塞io模型 , 优势是 处理效率很高,吞吐量巨大,能很快处理大文件,不仅可以 做 文件io操作, 还可以做sock ...
- SignalR 实现web浏览器客户端与服务端的推送功能
SignalR 是一个集成的客户端与服务器库,基于浏览器的客户端和基于 ASP.NET 的服务器组件可以借助它来进行双向多步对话. 换句话说,该对话可不受限制地进行单个无状态请求/响应数据交换:它将继 ...
- java客户端与服务端交互通用处理 框架解析
一.综述 java 客户端与服务端交互过程中,采用NIO通讯是异步的,客户端基本采用同一处理范式,来进行同异步的调用处理. 处理模型有以下几个要素: 1. NIO发送消息后返回的Future 2. 每 ...
- 基于开源SuperSocket实现客户端和服务端通信项目实战
一.课程介绍 本期带给大家分享的是基于SuperSocket的项目实战,阿笨在实际工作中遇到的真实业务场景,请跟随阿笨的视角去如何实现打通B/S与C/S网络通讯,如果您对本期的<基于开源Supe ...
- 在HTTP通讯过程中,是客户端还是服务端主动断开连接?
比如说:IE访问IIS,获取文件,肯定是要建立一个连接,这个连接在完成通讯后,是客户端Close了连接,还是服务端Close了连接.我用程序测模拟IE和IIS,都没有收到断开连接的消息,也就是都没有触 ...
- 客户端与服务端的事件watcher源码阅读
watcher存在的必要性 举个特容易懂的例子: 假如我的项目是基于dubbo+zookeeper搭建的分布式项目, 我有三个功能相同的服务提供者,用zookeeper当成注册中心,我的三个项目得注册 ...
- window安装rsync客户端和服务端
原文地址: https://www.cnblogs.com/janas/p/3321087.html 下载地址: https://linux.linuxidc.com/index.php?folder ...
- TCP学习之五:客户端、服务端异步传输字符串
参考学习张子阳大神的博客:http://www.cnblogs.com/JimmyZhang/category/101698.html 消息发送接口: 消息接收接口: 客户端: 服务端: 消息发送类: ...
随机推荐
- js 本地缓存localStorage
.localStorage - 没有时间限制的数据存储 ,,]; localStorage.setItem("stor",arr); console.log(localStorag ...
- java类(Class)的概念;对象的概念,声明类的属性 和方法,局部变量和成员变量,面向对象编程思维,抽象的概念
类(Class)的概念 类是对一组具有相同特征和行为的对象的抽象描述. 理解: [1] 类包含了两个要素:特性和行为 => 同一类事物具有相同的特征和行为. [2] 类是一个群体性概念.例如:网 ...
- 主席树——求区间[l,r]不同数字个数的模板(向左密集 D-query)
主席树的另一种用途,,(还有一种是求区间第k大,区间<=k的个数) 事实上:每个版本的主席树维护了每个值最后出现的位置 这种主席树不是以权值线段树为基础,而是以普通的线段树为下标的 /* 无修改 ...
- 洛谷 P2820 局域网
题目链接 https://www.luogu.org/problemnew/show/P2820 题目背景 某个局域网内有n(n<=100)台计算机,由于搭建局域网时工作人员的疏忽,现在局域网内 ...
- 理理Vue细节
理理Vue细节 1. 动态属性名:可使用表达式来设置动态属性名或方法名: <!-- 属性name --> <a :[name]="url"> ... < ...
- IBOS云办公系统二次开发之功能介绍(PHP技术)
IBOS自动化办公系统是我见到的功能.架构最好的开源自动化办公系统,功能与企业需求吻合度之高.架构之灵活,让我不得不将之介绍给大家,让跟多需要学习PHP开发的朋友来了解她,拥抱她! 如果您还没有很好的 ...
- 《团队作业第三、第四周》五小福团队作业--Scrum 冲刺阶段--Day7
<团队作业第三.第四周>五小福团队作业--Scrum 冲刺阶段--Day7 一.项目燃尽图 二.项目进展 [20172301郭恺第七天的进展] 第七天完成的任务: 代码整合,界面调整为相对 ...
- 基于Cmake+QT+VS的C++项目构建开发编译简明教程
目录 一.工具下载与安装 1. Qt 2. Visual Studio 2015 3. Cmake 二.C++及Qt项目构建 1. 基于VS构建Qt项目 2. ...
- 彻底卸载MySQL服务
前言 由于安装某个项目的执行文件,提示要卸载MySQL以便它自身MySQL安装,然后我禁用了MYSQL服务,再把这个文件夹删除后,发现还是提示请卸载MYSQL服务. ----------------- ...
- 【java】-- java反射机制
参考文章:https://blog.csdn.net/sinat_38259539/article/details/71799078 https://blog.csdn.net/wanderlu ...