前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

t-io?

作者头像
疯狂的KK
发布2023-01-12 18:06:53
5800
发布2023-01-12 18:06:53
举报
文章被收录于专栏:Java项目实战Java项目实战

如果没有t-io,华为这个智慧项目应该早就废了。

网络编程很苦,那是在使用t-io前的事。

与其坐学厚厚的《xxx权威指南》,不如站着自主研发,创造更多人一眼就懂的编程API

如此牛批中带着狂妄的t-io,到底是怎样的一个框架?

代码语言:javascript
复制
官网:https://www.tiocloud.com/

不见t-io,只有NIO

在接触网络应用程序框架之前,都是从IO,Buffer,Reactor,Channel来一步步学习的,即便是强大如Netty,也是需要IO理念基础,带着各种协议,特性慢慢才能理解Netty的一些工作原理,分析Netty的源码更是长篇大论,那么t-io又如何?是否有即见即可用的api?是否能媲美Netty的异步事件驱动?能进华为开源优选库的t-io到底多么深不可测?

在开发过程中,解决方案从来就不止一种,即便现在推崇Istio,ServiceMesh,但谁也不能说同类的产品有多么的让人诟病,bug让人难以忍受的地步,适合的,才是最好的。

即见树木,又见森林

既然Netty的学习过程那么辛苦,对于t-io我们就直接进入demo

首先启动项目非常丝滑,不需要改任何配置,当启动项目后开始监听,心跳检测为1秒,当发送消息后则会收到包内容

既然能收发到消息,并且打印日志与netty如出一辙,除了心跳检测和保持长连接,监听用户外,隐约可看到以Aio命名的监听器,先体验后付费,带着问题去看看工作原理。

这个官网的收发消息过程过于简洁了,把“包”编码发送到队列中,从队列中拿到buffer解码得到“包”就可以了。从handler入手

其核心步骤在如下的构造函数中,以websocketserver实现

代码语言:javascript
复制

public ShowcaseWebsocketStarter(int port, ShowcaseWsMsgHandler wsMsgHandler) throws Exception {
    wsServerStarter = new WsServerStarter(port, wsMsgHandler);
    加载配置信息
        serverTioConfig = wsServerStarter.getServerTioConfig();
    设置协议名称
    serverTioConfig.setName(ShowcaseServerConfig.PROTOCOL_NAME);
    serverTioConfig.setServerAioListener(ShowcaseServerAioListener.me);

//设置ip监控
    serverTioConfig.setIpStatListener(ShowcaseIpStatListener.me);
//设置ip统计时间段
    serverTioConfig.ipStats.addDurations(ShowcaseServerConfig.IpStatDuration.IPSTAT_DURATIONS);

//设置心跳超时时间
    serverTioConfig.setHeartbeatTimeout(ShowcaseServerConfig.HEARTBEAT_TIMEOUT);

    if (P.getInt("ws.use.ssl", 1) == 1) {
//如果你希望通过wss来访问,就加上下面的代码吧,不过首先你得有SSL证书(证书必须和域名相匹配,否则可能访问不了ssl)
//      String keyStoreFile = "classpath:config/ssl/keystore.jks";
//      String trustStoreFile = "classpath:config/ssl/keystore.jks";
//      String keyStorePwd = "214323428310224";


      String keyStoreFile = P.get("ssl.keystore", null);
      String trustStoreFile = P.get("ssl.truststore", null);
      String keyStorePwd = P.get("ssl.pwd", null);
      serverTioConfig.useSsl(keyStoreFile, trustStoreFile, keyStorePwd);
    }
  }

对比下Netty

代码语言:javascript
复制

@Override
  protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
    
    // websocket 基于http协议,所以要有http编解码器
    pipeline.addLast(new HttpServerCodec());
    // 对写大数据流的支持 
    pipeline.addLast(new ChunkedWriteHandler());
    // 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
    // 几乎在netty中的编程,都会使用到此hanler
    pipeline.addLast(new HttpObjectAggregator(1024*64));
    
    // ====================== 以上是用于支持http协议    ======================
    
    // ====================== 以下是支持httpWebsocket ======================
    
    /**
     * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
     * 本handler会帮你处理一些繁重的复杂的事
     * 会帮你处理握手动作:handshaking(close, ping, pong) ping + pong = 心跳
     * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同
     */
    pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
    
    // 自定义的handler
    pipeline.addLast(new ChatHandler());
  }

我觉得大体的思路还是一样的,都是websocket协议,自定义handler,一个基于buffer,一个基于stream,在监听方面同样处理也大体相同,因为服务监听肯定没什么区别,心跳检测,下线,上线这些。

从ShowcaseWsMsgHandler中可看到处理发送消息的主类Tio.java,这里有对群组和一对一发送到用户的实现,我们知道Netty是通过channel id来绑定用户对应关系的,而t-io来自于channelContext与Netty的channelHandlerContext很是相似。

消息发送的源码

代码语言:javascript
复制

private static Boolean sendToUser(TioConfig tioConfig, String userid, Packet packet, boolean isBlock) {
    获取userId对应的channel lock
    这里的读写锁是封装字ReentrantReadWriteLock
    SetWithLock<ChannelContext> setWithLock = tioConfig.users.find(tioConfig, userid);
    try {
      if (setWithLock == null) {
        return false;
      }

      ReadLock readLock = setWithLock.readLock();
      读锁
      readLock.lock();
      try {
        Set<ChannelContext> set = setWithLock.getObj();
        boolean ret = false;
        for (ChannelContext channelContext : set) {
          boolean singleRet = false;
// 不要用 a = a || b(),容易漏执行后面的函数
          借此判断是发送到群组还是指定channel
          if (isBlock) {
            singleRet = bSend(channelContext, packet);
          } else {
            singleRet = send(channelContext, packet);
          }
          if (singleRet) {
            ret = true;
          }
        }
        return ret;
      } catch (Throwable e) {
        log.error(e.getMessage(), e);
      } finally {
        readLock.unlock();
      }
      return false;
    } finally {
    }
  }

在bsend()或者send()的源码中可看到具体实现,但注释么,咩咩,太少了表示没看懂,大体还是用队列来处理消息的,如果不使用队列则使用bytebuffer来存储消息。最后返回消息是否发送成功,这里细节没有过多展示,专门解读源码的文章也很多,官方文档也算清晰,但跟想象中的不太一样。

代码语言:javascript
复制
     if (channelContext.tioConfig.useQueueSend) {
        isAdded = channelContext.sendRunnable.addMsg(packet);
      } else {
        isAdded = channelContext.sendRunnable.sendPacket(packet);
      }

风评如何

对于t-io的简单探索就到这里,总体体验下来,个人还是偏向Netty,先入为主的原因,感觉Netty更好理解,但整体框架也更繁重,向每一个开源作者致敬。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 赵KK日常技术记录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
SSL 证书
腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档