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 ...
随机推荐
- codeforces581D
Three Logos CodeForces - 581D Three companies decided to order a billboard with pictures of their lo ...
- kafka基本介绍
kafka基础知识 几个概念 kafka作为一个集群运行在一个或多个服务器上.kafka集群存储的消息是以topic为类别记录的.每个消息(也叫记录record,我习惯叫消息)是由一个key,一个va ...
- docker-lnmp dockerfile
code: FROM php:7.1.26-fpm WORKDIR /usr/share/nginx/html # bcmath pdo_mysql intl gd zip opcache xdebu ...
- 科学地增加postgresql最大连接数
PG配置文件路径 /etc/postgresql/9.3/main/postgresql.conf 首先如何查看最大连接数 This SQL will help you select max_conn ...
- spring 中的设计模式
https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247485205&idx=1&sn=63455d2313776d ...
- Spring Boot学习总结一
Spring Boot大大简化了之前java项目的繁琐xml配置,本文简单的总结下spring boot的相关知识. 1,@RestController 配置在controller中就是control ...
- CC1310 笔记
GPIO控制: #include <ti/drivers/GPIO.h> GPIO_init() 函数会调用 结构体实例 GPIOCC26XX_config,把需要使用到的GPIO放一起, ...
- 一、docker的原理
一.docker解决什么问题: 高效的利用资源 应用之间相互隔离 应用之间不能发生资源抢占,每个应用只能使用事先注册申请的资源. 环境封装,利于迁移 二.docker的原理: 1.Namespaces ...
- 分布式协调服务Zookeeper集群监控JMX和ZkWeb应用对比
分布式协调服务Zookeeper集群监控JMX和ZkWeb应用对比 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. JMX是用来远程监控Java应用的框架,这个也可以用来监控其他的J ...
- 常用Hadoop命令(bin)
**** bin 是二进制文件的意思,sbin....据说是superbin(管理员的bin) HDFS命令 某个文件的blocks信息 hadoop fsck /user/xx -files -bl ...