如果没有t-io,华为这个智慧项目应该早就废了。
网络编程很苦,那是在使用t-io前的事。
与其坐学厚厚的《xxx权威指南》,不如站着自主研发,创造更多人一眼就懂的编程API
如此牛批中带着狂妄的t-io,到底是怎样的一个框架?
官网: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实现
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
@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很是相似。
消息发送的源码
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来存储消息。最后返回消息是否发送成功,这里细节没有过多展示,专门解读源码的文章也很多,官方文档也算清晰,但跟想象中的不太一样。
if (channelContext.tioConfig.useQueueSend) {
isAdded = channelContext.sendRunnable.addMsg(packet);
} else {
isAdded = channelContext.sendRunnable.sendPacket(packet);
}
风评如何
对于t-io的简单探索就到这里,总体体验下来,个人还是偏向Netty,先入为主的原因,感觉Netty更好理解,但整体框架也更繁重,向每一个开源作者致敬。