vertx的NetServer模块
启动
public synchronized void listen(Handler<NetSocket> handler, SocketAddress socketAddress, Handler<AsyncResult<Void>> listenHandler) {
//检验
if (handler == null) {
throw new IllegalStateException("Set connect handler first");
}
if (listening) {
throw new IllegalStateException("Listen already called");
}
listening = true;
listenContext = vertx.getOrCreateContext();
registeredHandler = handler;//逻辑
synchronized (vertx.sharedNetServers()) {// 监听多个不同网络接口(ip:port) Netserver 防止并发
this.actualPort = socketAddress.port();
String hostOrPath = socketAddress.host() != null ? socketAddress.host() : socketAddress.path();
id = new ServerID(actualPort, hostOrPath);
NetServerImpl shared = vertx.sharedNetServers().get(id);
if (shared == null || actualPort == ) { // mutil instances 的情况,利用 mutli core cpu
/**
* frist instances
*/
serverChannelGroup = new DefaultChannelGroup("vertx-acceptor-channels", GlobalEventExecutor.INSTANCE);
// 采用单线程池,与HttpServer不同支出
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(availableWorkers);
sslHelper.validate(vertx);//验证ssl相关参数
bootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
/**
* connection accept 调度切换线程后触发
*/
protected void initChannel(Channel ch) throws Exception {
//限流策略,读大于写,导致内存无限扩大,最终 OOM
if (isPaused()) {
ch.close();//超过服务承载能力,关闭连接
return;
}
//根据 EventLoop 挑出一个verticle.handlers
HandlerHolder<Handlers> handler = handlerManager.chooseHandler(ch.eventLoop());
if (handler != null) {//逻辑处理不为Null
if (sslHelper.isSSL()) {//是否在TCP基础上添加TLS支持
io.netty.util.concurrent.Future<Channel> handshakeFuture;
if (options.isSni()) {//是否启用sni,单服务多证书情况
VertxSniHandler sniHandler = new VertxSniHandler(sslHelper, vertx);
handshakeFuture = sniHandler.handshakeFuture();
ch.pipeline().addFirst("ssl", sniHandler);
} else {
SslHandler sslHandler = new SslHandler(sslHelper.createEngine(vertx));
handshakeFuture = sslHandler.handshakeFuture();
ch.pipeline().addFirst("ssl", sslHandler);
}
//侦听 TLS handshark
handshakeFuture.addListener(future -> {
if (future.isSuccess()) {
connected(handler, ch);
} else {
Handler<Throwable> exceptionHandler = handler.handler.exceptionHandler;
if (exceptionHandler != null) {
handler.context.executeFromIO(() -> {
exceptionHandler.handle(future.cause());
});
} else {
log.error("Client from origin " + ch.remoteAddress() + " failed to connect over ssl: " + future.cause());
}
}
});
} else {
connected(handler, ch);
}
}
}
});
applyConnectionOptions(bootstrap);//添加Connection Accept之后的附属选项
//添加一个instaces(verticle的Handlers)到handlerManager中
handlerManager.addHandler(new Handlers(handler, exceptionHandler), listenContext);
try {
//绑定指定网络接口
bindFuture = AsyncResolveConnectHelper.doBind(vertx, socketAddress, bootstrap);
//侦听绑定结果
bindFuture.addListener(res -> {
if (res.succeeded()) {
Channel ch = res.result();
log.trace("Net server listening on " + (hostOrPath) + ":" + ch.localAddress());
if (NetServerImpl.this.actualPort != -) {//检查正确性
NetServerImpl.this.actualPort = ((InetSocketAddress)ch.localAddress()).getPort();
}
NetServerImpl.this.id = new ServerID(NetServerImpl.this.actualPort, id.host);
serverChannelGroup.add(ch);
//启动的NetServer服务(verticle)添加到Vertx.sharedHttpMap中
vertx.sharedNetServers().put(id, NetServerImpl.this);
//初始化metrics
VertxMetrics metrics = vertx.metricsSPI();
if (metrics != null) {
this.metrics = metrics.createMetrics(new SocketAddressImpl(id.port, id.host), options);
}
} else {
vertx.sharedNetServers().remove(id);
}
});
} catch (Throwable t) {
if (listenHandler != null) {
//出现异常回调给上层
vertx.runOnContext(v -> listenHandler.handle(Future.failedFuture(t)));
} else {
log.error(t);
}
listening = false;
return;
}
if (actualPort != ) {//尝试,bind成功,后续失败的情况
vertx.sharedNetServers().put(id, this);
}
actualServer = this;
} else {//other instances
actualServer = shared;
this.actualPort = shared.actualPort();
//初始化metrics
VertxMetrics metrics = vertx.metricsSPI();
this.metrics = metrics != null ? metrics.createMetrics(new SocketAddressImpl(id.port, id.host), options) : null;
//在actualServer基础上添加一个instaces(verticle的Handlers)到handlerManager中
actualServer.handlerManager.addHandler(new Handlers(handler, exceptionHandler), listenContext);
}
// 侦听 bind 结果
actualServer.bindFuture.addListener(res -> {
if (listenHandler != null) {
AsyncResult<Void> ares;
if (res.succeeded()) {
ares = Future.succeededFuture();
} else {
listening = false;
ares = Future.failedFuture(res.cause());
}
//结果回调上层
listenContext.runOnContext(v -> listenHandler.handle(ares));
} else if (res.failed()) {
log.error("Failed to listen", res.cause());
listening = false;
}
});
}
return;
}
处理
private void connected(HandlerHolder<Handlers> handler, Channel ch) {
EventLoop worker = ch.eventLoop();
//配置context映射,因为eventloopSize < verticle Size情况 ; 1 eventloop: N verticle
ContextImpl.setContext(handler.context);
NetServerImpl.this.initChannel(ch.pipeline());//初始化属性和配置
VertxNetHandler nh = new VertxNetHandler(ctx -> new NetSocketImpl(vertx, ctx, handler.context, sslHelper, metrics)) {
@Override
/**
* 接收消息处理
* @param connection 客户端连接
* @param context 当前 verticle 上下文
* @param msg 接收的消息对象
*/
protected void handleMessage(NetSocketImpl connection, ContextImpl context, ChannelHandlerContext chctx, Object msg) throws Exception {
connection.handleMessageReceived(msg);
}
};
//为了调用close方法释放socket资源
nh.addHandler(conn -> socketMap.put(ch, conn));
nh.removeHandler(conn -> socketMap.remove(ch));
ch.pipeline().addLast("handler", nh);//添加消息逻辑处理
NetSocketImpl sock = nh.getConnection();//获取当前连接
handler.context.executeFromIO(() -> {
if (metrics != null) {
sock.metric(metrics.connected(sock.remoteAddress(), sock.remoteName()));
}
//client connection 处理
handler.handler.connectionHandler.handle(sock);
});
}
note: NetServer 与 HttpServer 不同处在Http大量短连接请求,所以采用单独线程池处理connection/accept,
NetServer是单线程池模型,其中有一个EventLoop(Thread)还需额外处理client/accept事件,切记不在
Eventloop中做阻塞操作,需额外处理client/accept 的EventLoop处理时间过长,会造成client connection慢
的现象.
vertx的NetServer模块的更多相关文章
- vertx的HttpServer模块
Start HttpServer /** * 启动 HttpServer * multi instances 采用 synchronized防止线程安全问题 * addHandlers 方法是acto ...
- linux安装perl模块
查询perl CPAN模块 shell>perl -MCPAN -e shell cpan>install module_name 手动安装perl CPAN模块 从 CPAN(h ...
- perl模块安装
转自: http://www.cnblogs.com/itech/archive/2009/08/10/1542832.html http://www.mike.org.cn/blog/index.p ...
- vertx模块HAManager高可用
HAManager public HAManager(VertxInternal vertx, DeploymentManager deploymentManager, ClusterManager ...
- vertx模块DeploymentManager部署管理器
DeploymentManager public DeploymentManager(VertxInternal vertx) { this.vertx = vertx; loadVerticleFa ...
- Vertx.vertx()初始框图和模块
Vertx.vertx()实例 一.构造方法 1. VertxImpl构造方法 选择 transports protocol , default select 模型 if (options.getPr ...
- vertx实例的fileSystem文件系统模块
初始化 //根据OS区分实现 System.getProperty("os.name").toLowerCase(); Utils.isWindows() ? new Window ...
- Vertx eventbus模块解析
eventbus 事件總線 協議棧 TCP分包,粘包解決採用方案: 消息定长(定義消息体總长度),消息分为消息头和消息体 dataType bytes description int 4 包体总大小 ...
- 开始学nodejs——net模块
net模块的组成部分 详见 http://nodejs.cn/api/net.html 下面整理出了整个net模块的知识结构,和各个事件.方法.属性的用法 net.Server类 net.Socket ...
随机推荐
- 【学习笔记】JS知识点整理
1 原型/原型链 1-1 原型 定义:原型是function对象的一个属性,定义了构造函数制造出的对象的公共祖先.通过该构造函数产生的对象,可以继承该原型的属性和方法. 原型是一个对象. 可以利用原型 ...
- CF 441E Valera and Number
CF 441E Description 一共执行\(k\)次,每次有\(p\%\)把\(x * 2\),有\((100 - p)\%\)把\(x + 1\).问二进制下\(x\)末尾期望\(0\)的个 ...
- spring IOC与AOP
Spring IOC容器 spring IOC 容器有两种,分别是 BeanFactory 容器和 ApplicationContext 容器. BeanFactory如下: /*第一步,利用Clas ...
- 20175209 实验二《Java面向对象程序设计》实验报告
20175209 实验二<Java面向对象程序设计>实验报告 一.实验前期准备 了解三种代码 伪代码 产品代码 测试代码 我们先写伪代码,伪代码 从意图层面来解决问题: 有了伪代码 我们用 ...
- java 键盘录入(Scanner)
键盘录入(Scanner)• 键盘录入数据概述– 我们目前在写程序的时候, 数据值都是固定的, 但是实际开发中, 数据值肯定是变化的, 所以, 把数据改进为键盘录入, 提高程序的灵活性.• 如何实现键 ...
- 野路子码农系列(1) 创建Web API
新工作正式开始了2天,由于客户暂时还没交接数据过来,暂时无事可做.恰逢政佬给某超市做的商品图像识别的项目客户催收了,老板要求赶紧搞个API,于是我就想我来试试吧. 说起API,我其实是一窍不通的,我对 ...
- DirectX11--实现一个3D魔方(3)
前言 (2019/1/9 09:23)上一章我们主要讲述了魔方的旋转,这个旋转真是有毒啊,搞完这个部分搭键鼠操作不到半天应该就可以搭完了吧... (2019/1/9 21:25)啊,真香 有人发这张图 ...
- 使用Docker安装SonarQube
需先安装docker和docker-compose.见:https://www.cnblogs.com/hackyo/p/9280042.html 在任意目录下新建文件docker-compose.y ...
- C# bool.tryparse
才工作时候是做C++的,受这个影响一直以为C# 转换 “0” 和 "false"会转换为 false,“1”和"true"转换为true,原来只有“true”才 ...
- 多项式求导系列——OO Unit1分析和总结
一.摘要 本文是BUAA OO课程Unit1在课程讲授.三次作业完成.自测和互测时发现的问题,以及倾听别人的思路分享所引起个人的一些思考的总结性博客.本文第二部分介绍三次作业的设计思路,主要以类图的形 ...