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 ...
随机推荐
- iPhone 系统刷机
1. 下载好固件(爱思 或者 pp助手) e.g. http://jailbreak.25pp.com/gujian/ 2. 将电脑与手机连接上,弹出iTunes软件即可 3. 长按手机电源键 关闭手 ...
- 树莓派3B+(三)
上一篇中,我们配置好了基本的raspbain系统,接下来我们可以用xrdp或者vnc在Windows上远程连接树莓派. 一.安装xrdp xrdp和vnc是两种常见的远程桌面协议,可以进行可视化界面远 ...
- python面试题整合
面试题整合 面试题—并发编程部分
- BZOJ 2730 矿场搭建
割点 割点以外的点坍塌不影响其他人逃生,因为假设我们任取两个个非割点s建立救援站,非割点的任意点坍塌,我们都可以从割点走到一个救援出口. 所以我们只考虑割点坍塌的情况. 我们可以先找出图中所有的割点. ...
- loj2977 巧克力 (斯坦纳树+随机化)
考虑颜色比较少的时候,第一问可以直接斯坦纳树 第二问考虑二分,每次把每格的权值给成1000+[a[i]>m],就是在个数最少的基础上尽量选小于等于m的 然而颜色太多不能直接做,但可以把每种颜色映 ...
- django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
异常汇总:https://www.cnblogs.com/dotnetcrazy/p/9192089.html 这个是Django对MySQLdb版本的限制,我们使用的是PyMySQL,所以不用管它 ...
- php对某个页面设置基础认证登录设置
记录下. 对某个页面设置认证 代码最开始添加: <?php $user = 'test'; $password = '111111'; // 通过HTTP认证进行验证 if (!isset($_ ...
- logstash的output配置中指定elasticsearch的template
转自:https://blog.csdn.net/felix_yujing/article/details/78930389 之前采用的是通过filebeat收集nginx的日志,直接到elastic ...
- 【洛谷P1659】啦啦队排练
题目大意:给定一个长度为 N 的字符串,求前 K 个长度为奇数的回文子串的长度的乘积是多少. 题解:利用回文自动机,将所有长度的回文串和个数求出来,按照长度排序进行模拟即可. 代码如下 // luog ...
- 将CSV文件存为HTML文件形式
# -*- coding: utf-8 -*- """ Created on Mon Apr 29 09:24:04 2019 @author: history &quo ...