启动

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模块的更多相关文章

  1. vertx的HttpServer模块

    Start HttpServer /** * 启动 HttpServer * multi instances 采用 synchronized防止线程安全问题 * addHandlers 方法是acto ...

  2. linux安装perl模块

    查询perl CPAN模块   shell>perl -MCPAN -e shell cpan>install module_name   手动安装perl CPAN模块 从 CPAN(h ...

  3. perl模块安装

    转自: http://www.cnblogs.com/itech/archive/2009/08/10/1542832.html http://www.mike.org.cn/blog/index.p ...

  4. vertx模块HAManager高可用

    HAManager public HAManager(VertxInternal vertx, DeploymentManager deploymentManager, ClusterManager ...

  5. vertx模块DeploymentManager部署管理器

    DeploymentManager public DeploymentManager(VertxInternal vertx) { this.vertx = vertx; loadVerticleFa ...

  6. Vertx.vertx()初始框图和模块

    Vertx.vertx()实例 一.构造方法 1. VertxImpl构造方法 选择 transports protocol , default select 模型 if (options.getPr ...

  7. vertx实例的fileSystem文件系统模块

    初始化 //根据OS区分实现 System.getProperty("os.name").toLowerCase(); Utils.isWindows() ? new Window ...

  8. Vertx eventbus模块解析

    eventbus 事件總線 協議棧 TCP分包,粘包解決採用方案: 消息定长(定義消息体總长度),消息分为消息头和消息体 dataType bytes description int 4 包体总大小 ...

  9. 开始学nodejs——net模块

    net模块的组成部分 详见 http://nodejs.cn/api/net.html 下面整理出了整个net模块的知识结构,和各个事件.方法.属性的用法 net.Server类 net.Socket ...

随机推荐

  1. python 元组用法

    tup1 = ('physics', 'chemistry', 1997, 2000) 元组中的元素值是不允许修改的 序号 方法及描述 1 cmp(tuple1, tuple2)比较两个元组元素. 2 ...

  2. (简单)华为Nova青春 WAS-AL00的USB调试模式在哪里开启的流程

    就在我们使用Pc接通安卓手机的时候,如果手机没有开启usb开发者调试模式,Pc则无办法成功检测到我们的手机,在一些情况下,我们使用的一些功能较强的app好比之前我们使用的一个app引号精灵,老版本就需 ...

  3. Codeforces Round #523 (Div. 2) D. TV Shows 模拟(多重集 先把所有区间加入多重集合)+贪心+二分

    题意:给出n个电视节目的起始和结束时间  并且租一台电视需要x +y*(b-a)  [a,b]为时段 问完整看完电视节目的最小花费是多少 思路:贪心的思想 情况1 如果新租一台电视的花费<=在空 ...

  4. 执行Git命令时出现各种 SSL certificate problem 的解决办法

    执行Git命令时出现各种 SSL certificate problem 的解决办法 来源  https://www.cnblogs.com/chenzc/p/5842932.html 比如我在win ...

  5. [HNOI2010]城市建设

    [HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...

  6. Nginx下配置SSL模块,支持https

    Http与Https的区别 HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效 ...

  7. 快速掌握Nginx(四) —— Nginx日志切片和常用配置总结

    1.Nginx日志管理 1.日志简单介绍 Nginx提供了日志记录的功能,日志文件在对我们管理网站十分有用,通过访问日志(access_log)我们可以获取请求来源.客户端信息.请求的资源等信息:通过 ...

  8. beego学习2 控制器与路由

    beego控制器 controller目录新建test.go文件 结构体集成beego.Controller 控制名需大写,否则为私有方法 package controllers import ( & ...

  9. DirectX11--HLSL编译着色器的三种方法

    前言 本教程不考虑Effects11(FX11),而是基于原始的HLSL. 目前编译与加载着色器的方法如下: 使用Visual Studio中的HLSL编译器,随项目编译期间一同编译,并生成.cso( ...

  10. Shell脚本统计文件行数

    Shell脚本统计文件行数 转自 http://www.jb51.net/article/61943.htm    示例:row_count.sh文件 awk '{print NR}' row_cou ...