首页 文章 精选 留言 我的

精选列表

搜索[高性能通信库],共10026篇文章
优秀的个人博客,低调大师

高性能网络通信框架Netty-Netty客户端底层与Java NIO对应关系

5.1 Netty客户端底层与Java NIO对应关系 在讲解Netty客户端程序时候我们提到指定NioSocketChannel用于创建客户端NIO套接字通道的实例,下面我们来看NioSocketChannel是如何创建一个Java NIO里面的SocketChannel的。 首先我们来看NioSocketChannel的构造函数: public NioSocketChannel() { this(DEFAULT_SELECTOR_PROVIDER); } 其中DEFAULT_SELECTOR_PROVIDER定义如下: private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider(); 然后继续看 //这里的provider为DEFAULT_SELECTOR_PROVIDER public NioSocketChannel(SelectorProvider provider) { this(newSocket(provider)); } 其中newSocket代码如下: private static SocketChannel newSocket(SelectorProvider provider) { try { return provider.openSocketChannel(); } catch (IOException e) { throw new ChannelException("Failed to open a socket.", e); } } 所以NioSocketChannel内部是管理一个客户端的SocketChannel的,这个SocketChannel就是讲Java NIO时候的SocketChannel,也就是创建NioSocketChannel实例对象时候相当于执行了Java NIO中: SocketChannel socketChannel = SocketChannel.open(); 另外在NioSocketChannel的父类AbstractNioChannel的构造函数里面默认会记录队op_read事件感兴趣,这个后面当链接完成后会使用到: protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) { super(parent, ch, SelectionKey.OP_READ); } 另外在NioSocketChannel的父类AbstractNioChannel的构造函数里面设置了该套接字为非阻塞的 protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent); this.ch = ch; this.readInterestOp = readInterestOp; try { ch.configureBlocking(false); } catch (IOException e) { ... } } 下面我们看Netty里面是哪里创建的NioSocketChannel实例,哪里注册到选择器的。 下面我们看下Bootstrap的connect操作代码: public ChannelFuture connect(InetAddress inetHost, int inetPort) { return connect(new InetSocketAddress(inetHost, inetPort)); } 类似Java NIO传递了一个InetSocketAddress对象用来记录服务端ip和端口: public ChannelFuture connect(SocketAddress remoteAddress) { ... return doResolveAndConnect(remoteAddress, config.localAddress()); } 下面我们看下doResolveAndConnect的代码: private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) { //(1) final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.isDone()) { if (!regFuture.isSuccess()) { return regFuture; } //(2) return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise()); } ... } } 首先我们来看代码(1)initAndRegister: final ChannelFuture initAndRegister() { Channel channel = null; try { //(1.1) channel = channelFactory.newChannel(); //(1.2) init(channel); } catch (Throwable t) { ... } //(1.3) ChannelFuture regFuture = config().group().register(channel); if (regFuture.cause() != null) { if (channel.isRegistered()) { channel.close(); } else { channel.unsafe().closeForcibly(); } } } 其中(1.1)作用就是创建一个NioSocketChannel的实例,代码(1.2)是具体设置内部套接字的选项的。 代码(1.3)则是具体注册客户端套接字到选择器的,其首先会调用NioEventLoop的register方法,最后调用NioSocketChannelUnsafe的register方法: public final void register(EventLoop eventLoop, final ChannelPromise promise) { ... AbstractChannel.this.eventLoop = eventLoop; if (eventLoop.inEventLoop()) { register0(promise); } else { try { eventLoop.execute(new Runnable() { @Override public void run() { register0(promise); } }); } catch (Throwable t) { ... } } } 其中 register0内部调用doRegister,其代码如下: protected void doRegister() throws Exception { boolean selected = false; for (;;) { try { //注册客户端socket到当前eventloop的selector上 selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this); return; } catch (CancelledKeyException e) { ... } } } 到这里代码(1)initAndRegister的流程讲解完毕了,下面我们来看代码(2)的 public final void connect( final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) { ... try { ... boolean wasActive = isActive(); if (doConnect(remoteAddress, localAddress)) { fulfillConnectPromise(promise, wasActive); } else { 。。。 } } catch (Throwable t) { ... } } 其中doConnect代码如下: protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { ... boolean success = false; try { //2.1 boolean connected = SocketUtils.connect(javaChannel(), remoteAddress); //2.2 if (!connected) { selectionKey().interestOps(SelectionKey.OP_CONNECT); } success = true; return connected; } finally { if (!success) { doClose(); } } } 其中2.1具体调用客户端套接字的connect方法,等价于Java NIO里面的。 代码2.2 由于connect 方法是异步的,所以类似JavaNIO调用connect方法进行判断,如果当前没有完成链接则设置对op_connect感兴趣。 最后一个点就是何处进行的从选择器获取就绪的事件的,具体是在该客户端套接关联的NioEventLoop里面的做的,每个NioEventLoop里面有一个线程用来循环从选择器里面获取就绪的事件,然后进行处理: protected void run() { for (;;) { try { ... select(wakenUp.getAndSet(false)); ... processSelectedKeys(); ... } catch (Throwable t) { handleLoopException(t); } ... } } 其中select代码如下: private void select(boolean oldWakenUp) throws IOException { Selector selector = this.selector; try { ... for (;;) { ... int selectedKeys = selector.select(timeoutMillis); selectCnt ++; ... } catch (CancelledKeyException e) { ... } } 可知会从选择器选取就绪的事件,其中processSelectedKeys代码如下: private void processSelectedKeys() { ... processSelectedKeysPlain(selector.selectedKeys()); ... } 可知会获取已经就绪的事件集合,然后交给processSelectedKeysPlain处理,后者循环调用processSelectedKey具体处理每个事件,代码如下: private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { ... try { //(3)如果是op_connect事件 int readyOps = k.readyOps(); if ((readyOps & SelectionKey.OP_CONNECT) != 0) { int ops = k.interestOps(); ops &= ~SelectionKey.OP_CONNECT; k.interestOps(ops); //3.1 unsafe.finishConnect(); } //4 if ((readyOps & SelectionKey.OP_WRITE) != 0) { ch.unsafe().forceFlush(); } //5 if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { unsafe.read(); } } catch (CancelledKeyException ignored) { unsafe.close(unsafe.voidPromise()); } } 代码(3)如果当前事件key为op_connect则去掉op_connect,然后调用NioSocketChannel的doFinishConnect: protected void doFinishConnect() throws Exception { if (!javaChannel().finishConnect()) { throw new Error(); } } 可知是调用了客户端套接字的finishConnect方法,最后会调用NioSocketChannel的doBeginRead方法设置对op_read事件感兴趣: protected void doBeginRead() throws Exception { ... final int interestOps = selectionKey.interestOps(); if ((interestOps & readInterestOp) == 0) { selectionKey.interestOps(interestOps | readInterestOp); } } 这里interestOps为op_read,上面在讲解NioSocketChannel的构造函数时候提到过。 代码(5)如果当前是op_accept事件说明是服务器监听套接字获取到了一个链接套接字,如果是op_read,则说明可以读取客户端发来的数据了,如果是后者则会激活管线里面的所有handler的channelRead方法,这里会激活我们自定义的NettyClientHandler的channelRead读取客户端发来的数据,然后在向客户端写入数据。 5.2 总结 本节讲解了Netty客户端底层如何使用Java NIO进行实现的,可见与我们前面讲解的Java NIO设计的客户端代码步骤是一致的,只是netty对其进行了封装,方便了我们使用,了解了这些对深入研究netty源码提供了一个骨架指导。 原文发布时间为:2018-06-8 本文来自云栖社区合作伙伴“并发编程网 - ifeve.com”,了解相关信息可以关注“并发编程网 - ifeve.com”。

优秀的个人博客,低调大师

Redis 6.2-RC3 发布,高性能内存数据

Redis 6.2-RC3 发布了,这是 6.2 系列的第 3 个候选者版本,与 RC2 相比有更完整的更新列表。 主要更新内容 新命令/参数 添加 HRANDFIELD 和 ZRANDMEMBER 命令 添加 FAILOVER 命令 添加 GETEX、GETDEL命令 SET 命令增加PXAT/EXAT 参数 FLUSHALL 和 FLUSHDB 命令增加 SYNC 参数,SCRIPT FLUSH命令增加ASYNC/SYNC 参数 Sentinel 向 Sentinel 添加主机名支持 防止文件描述符泄漏到 Sentinel 脚本中 修复配置文件行顺序依赖性和配置重写顺序 新的配置选项 添加 set-proc-title 配置选项以禁用对进程标题的更改 添加 proc-title-template 选项以控制进程标题中显示的内容 添加 lazyfree-lazy-user-flush 配置选项以控制 FLUSHALL、FLUSHDB 和 SCRIPT FLUSH Bug 修复 AOF:通过打开/关闭 appendonly 配置从上次写入错误中恢复 当 AOF fsync 策略为“总是”时,退出 fsync 错误 测试 arm64 CoW 错误时,避免断言(在较早的内核上) CONFIG REWRITE 应该接受 umask 设置 修复某些命令中的 firstkey、lastkey 和 step 详细内容请查看更新公告。

优秀的个人博客,低调大师

FST(fast-serialization)3.0.0 发布,高性能序列化

FST(fast-serialization)3.0.0发布了。FST 是一个 Java 快速对象序列化开发包,100% 兼容原生 JDK 环境,并且序列化速度快 10 倍。 此版本开始支持 JDK 14,JDK 14 的 inkubator 模块中包括了新的“外部内存访问” API,用于替换掉堆文件和映射文件的无用 API。 <dependency> <groupId>de.ruedigermoeller</groupId> <artifactId>fst</artifactId> <version>3.0.1</version> </dependency> 同时删除了 structs,详情查看更新说明:https://github.com/RuedigerMoeller/fast-serialization/releases/tag/3.0.0

优秀的个人博客,低调大师

YugabyteDB 2.1.2 发布,高性能分布式 SQL 数据

YSQL的变化 [YSQL]表达式下push框架。#3297 [YSQL]通过减少主RPC的数量来优化relcache预加载。#3049 [YSQL] [Diesel ORM]修复了带有设置返回功能和LIMIT的嵌套SELECT的崩溃问题。#3811 [YSQL]修复ybctid值与分区边界匹配时的错误。#3833 [YSQL] [Hasura]使用RETURNING子句修复UPDATE的“缺少基表ybctid”错误。#3805 [YSQL]对具有多个FK表的表进行更新会使postgres崩溃。#3583 系统改进 [cdc]修复DeleteTableWithCDCStream 确保只有平板电脑负责人才能确认变更表。#2236 使OpenSSL使用线程安全。#3454 从RequestConsensusVote恢复已删除的超时。#3390 托管:在UI表格页面(#3726)上修复DFATAL。#3726 在更新CQL索引时,忽略来自同一事务的写入。#3718 更新默认压缩线程数的设置。#3561 向交易参与者添加解决意图的功能。#1032 [cdc]能够在yb-admin中删除和列出CDC流。#3638 将默认的清单预分配设置为64k。#3666 加密计数器溢出的解决方法。#3707 修复了网络分区期间的SecureStream OOM。#3842 写入停止后,事务可能会挂在事务参与者上。#3823 在主/任务处显示回填进度。#3668 修复已删除平板电脑的交易应用。#3828 注释掉Connection :: Shutdown信息日志。#3842 平台 修复了启用YSQL身份验证时的运行状况检查失败。#3737 复制不足的服务器添加到主健康检查。#1374 进入Yugabyte Cloud上的“表格”页面时,修复Tab问题。#3749 仅保存可用的AWS实例类型。#3626 添加了用于查询审计表的API。#3792 为启用TLS的Universe生成客户端证书。#3839 Onprem-允许指定homeDir,自动排除安装s3cmd和ntp。#3834 默认情况下,将排序添加到发布列表以及搜索栏,以允许用户通过输入字符串的一部分来快速访问所需的发布。#3563 正确禁用onprem的ntp安装

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册