基于t-io的MI工具实现
原文:https://my.oschina.net/u/2984386/blog/1630300
背景介绍
t-io是一款国产开源的网络编程框架,主要是特点:简单,易上手,AIP封装通俗易懂,适合一般企业简易即时通讯工具开发。宣传性能也不错:百万TCP长连接,不过个人也没测试过,所以想试一试看看。本文档主要记录了简单群组聊天的实现,同时记录下学习t-io的过程。其实 http://t-io.org/#/ 中有比较完整的Demo,本文也主要是参考其中。
服务端
启动类:
package com.dooper.server;
import org.tio.server.AioServer;
import org.tio.server.ServerGroupContext;
import org.tio.server.intf.ServerAioListener;
import com.dooper.common.packet.Constant;
import com.dooper.server.handler.MyServerAioHandler;
public class ServerStarter {
public static MyServerAioHandler aioHandler = new MyServerAioHandler();
public static ServerAioListener aioListener = null;
public static ServerGroupContext serverGroupContext = new ServerGroupContext(aioHandler, aioListener);
public static AioServer aioServer = new AioServer(serverGroupContext);
public static String serverIp = null;
public static int serverPort = Constant.PORT;
public static void main(String[] args) throws Exception{
serverGroupContext.setHeartbeatTimeout(Constant.TIMEOUT);
aioServer.start(serverIp, serverPort);
}
}
消息处理
消息处理中有绑定组的步骤,实际不应该在此处,应该是有额外的处理类来处理群组绑定,此处因为懒,直接写在里面了。
package com.dooper.server.handler;
import java.nio.ByteBuffer;
import org.tio.core.Aio;
import org.tio.core.ChannelContext;
import org.tio.core.GroupContext;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;
import org.tio.server.intf.ServerAioHandler;
import com.dooper.common.packet.MyPacket;
/**
* server
*
*
*/
public class MyServerAioHandler implements ServerAioHandler{
@Override
public Packet decode(ByteBuffer buffer, ChannelContext chanelContext) throws AioDecodeException {
int readableLength = buffer.limit() - buffer.position();
if(readableLength < MyPacket.HEADER_LENGHT){
return null;
}
int bodyLength = buffer.getInt();
if(bodyLength<0){
throw new AioDecodeException("bodyLength ["+bodyLength+"] is not rigth,remote"+chanelContext.getClientNode());
}
int neededLength = MyPacket.HEADER_LENGHT+bodyLength;
int isDataEnough = readableLength - neededLength;
if(isDataEnough < 0){
return null;
}else{
MyPacket packet = new MyPacket();
if(bodyLength > 0){
byte[] dst = new byte[bodyLength];
buffer.get(dst);
packet.setBody(dst);
}
return packet;
}
}
@Override
public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) {
MyPacket myPacket = (MyPacket)packet;
byte[] body = myPacket.getBody();
int bodyLen = 0;
if(body != null){
bodyLen = body.length;
}
int allLen = MyPacket.HEADER_LENGHT + bodyLen;
ByteBuffer buffer = ByteBuffer.allocate(allLen);
buffer.order(groupContext.getByteOrder());
buffer.putInt(bodyLen);
if(body != null){
buffer.put(body);
}
return buffer;
}
@Override
public void handler(Packet packet, ChannelContext channelContext) throws Exception {
MyPacket myPacket = (MyPacket)packet;
byte[] body = myPacket.getBody();
if(body != null){
String str = new String(body,MyPacket.CHARSET);
System.out.println("客户端发送的消息:"+str);
Aio.bindGroup(channelContext, "group1");
GroupHandler gh = new GroupHandler();
gh.handler(myPacket, channelContext);
}
return;
}
}
自定义的群组消息处理
package com.dooper.server.handler;
import org.tio.core.Aio;
import org.tio.core.ChannelContext;
import org.tio.core.intf.Packet;
import com.dooper.common.packet.MyPacket;
public class GroupHandler extends MsgHandler{
@Override
public void handler(Packet packet, ChannelContext channelContext) throws Exception {
MyPacket myPacket = (MyPacket)packet;
byte[] body = myPacket.getBody();
if(body!=null){
MyPacket mp = new MyPacket();
System.out.println("服务端收到消息:"+new String(body,MyPacket.CHARSET));
mp.setBody((channelContext.getClientNode()+":"+new String(body,MyPacket.CHARSET)).getBytes(MyPacket.CHARSET));
Aio.sendToGroup(channelContext.getGroupContext(), "group1", mp);
}
}
}
客户端
启动类
package com.dooper.client;
import java.util.Scanner;
import org.tio.client.AioClient;
import org.tio.client.ClientChannelContext;
import org.tio.client.ClientGroupContext;
import org.tio.client.ReconnConf;
import org.tio.client.intf.ClientAioHandler;
import org.tio.client.intf.ClientAioListener;
import org.tio.core.Aio;
import org.tio.core.Node;
import com.dooper.common.packet.Constant;
import com.dooper.common.packet.MyPacket;
public class MyClientStarter {
public static Node serverNode = new Node(Constant.SERVER,Constant.PORT);
public static ClientAioHandler aioClientHandler = new MyClientAioHandler();
public static ClientAioListener aioListener = null;
private static ReconnConf reconnConf = new ReconnConf(5000L);
private static ClientGroupContext clientGroupContext = new ClientGroupContext(aioClientHandler, aioListener,reconnConf);
public static AioClient aioClient = null;
public static ClientChannelContext clientChannelContext = null;
public static void main(String[] args) throws Exception{
clientGroupContext.setHeartbeatTimeout(Constant.TIMEOUT);
aioClient = new AioClient(clientGroupContext);
clientChannelContext = aioClient.connect(serverNode);
Scanner sc = new Scanner(System.in);
System.out.println("请发送群组消息:");
String line = sc.nextLine(); // 这个就是用户输入的数据
while (true) {
if ("exit".equalsIgnoreCase(line)) {
System.out.println("Thanks for using! bye bye.");
break;
} else{
sendGroup(line);
}
line = sc.nextLine(); // 这个就是用户输入的数据
}
// send();
sc.close();
}
public static void send() throws Exception{
MyPacket packet = new MyPacket();
packet.setBody("hello world".getBytes(MyPacket.CHARSET));
Aio.send(clientChannelContext, packet);
}
public static void sendGroup(String msg) throws Exception{
Aio.bindGroup(clientChannelContext, "group1");
MyPacket packet = new MyPacket();
packet.setBody(msg.getBytes(MyPacket.CHARSET));
Aio.sendToGroup(clientGroupContext, "group1", packet);
}
}
消息处理类
package com.dooper.client;
import java.nio.ByteBuffer;
import org.tio.client.intf.ClientAioHandler;
import org.tio.core.ChannelContext;
import org.tio.core.GroupContext;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;
import com.dooper.common.packet.MyPacket;
public class MyClientAioHandler implements ClientAioHandler {
private static MyPacket heartbeatPacket = new MyPacket();
/**
* ���룺
*/
@Override
public Packet decode(ByteBuffer buffer, ChannelContext channelContext) throws AioDecodeException {
int readableLength = buffer.limit() - buffer.position();
if(readableLength < MyPacket.HEADER_LENGHT){
return null;
}
int bodyLength = buffer.getInt();
if(bodyLength < 0){
throw new AioDecodeException("bodyLength ["+bodyLength+"] is not right,remote:"+channelContext.getClientNode());
}
int neededLength = MyPacket.HEADER_LENGHT + bodyLength;
int isDataEnough = readableLength - neededLength;
if(isDataEnough < 0){
return null;
}else{
MyPacket myPacket = new MyPacket();
if(bodyLength > 0){
byte[] dst = new byte[bodyLength];
buffer.get(dst);
myPacket.setBody(dst);
}
return myPacket;
}
}
/**
* ���룺
*/
@Override
public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) {
MyPacket myPacket = (MyPacket)packet;
byte[] body = myPacket.getBody();
int bodyLen = 0;
if(body != null){
bodyLen = body.length;
}
int allLen = MyPacket.HEADER_LENGHT +bodyLen;
ByteBuffer buffer = ByteBuffer.allocate(allLen);
buffer.order(groupContext.getByteOrder());
buffer.putInt(bodyLen);
if(body != null){
buffer.put(body);
}
return buffer;
}
@Override
public void handler(Packet packet, ChannelContext channelContext) throws Exception {
MyPacket myPacket = (MyPacket)packet;
byte[] body = myPacket.getBody();
if(body!=null){
String str = new String(body,MyPacket.CHARSET);
System.out.println(str);
}
return ;
}
@Override
public Packet heartbeatPacket() {
return heartbeatPacket;
}
}
基于t-io的MI工具实现的更多相关文章
- 在线白板,基于socket.io的多人在线协作工具
首发:个人博客,更新&纠错&回复 是昨天这篇博文留的尾巴,socket.io库的使用练习,成品地址在这里. 代码已经上传到github,传送门.可以开俩浏览器看效果. 现实意义是俩人在 ...
- Hive -- 基于Hadoop的数据仓库分析工具
Hive是一个基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库 ...
- 基于Web的IIS管理工具
Servant:基于Web的IIS管理工具 Servant for IIS是个管理IIS的简单.自动化的Web管理工具.安装Servant的过程很简单,只要双击批处理文件Install Serva ...
- 搭建基于MySQL的读写分离工具Amoeba
搭建基于MySQL的读写分离工具Amoeba: Amoeba工具是实现MySQL数据库读写分离的一个工具,前提是基于MySQL主从复制来实现的: 实验环境(虚拟机): 主机 角色 10.10.10.2 ...
- ART模式下基于Xposed Hook开发脱壳工具
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78092365 Dalvik模式下的Android加固技术已经很成熟了,Dalvik ...
- Processon 一款基于HTML5的在线作图工具
CSDN的蒋涛不久前在微博上评价说ProcessOn是web版的visio,出于好奇私下对ProcessOn进行了一番研究.最后发现无论是在用户体验上,还是在技术上,ProcessOn都比微软的Vis ...
- 基于数据库的自动化生成工具,自动生成JavaBean、自动生成数据库文档等(v4.1.2版)
目录: 第1版:http://blog.csdn.net/vipbooks/article/details/51912143 第2版:htt ...
- 基于socket.io的实时在线选座系统
基于socket.io的实时在线选座系统(demo) 前言 前段时间公司做一个关于剧院的项目,遇到了这样一种情况. 在高并发多用户同时选座的情况下,假设A用户进入选座页面,正在选择座位,此时还没有提交 ...
- 基于 socket.io 的 AI 服务 杂谈
为什么会想到来聊下这个话题. 前几天在公司的项目中,开发一个基于 socket.io 的直播 IM 功能. 直播分为两部分,一部分是比较昂贵的 视频推流, 另外一部分是 IM 即时聊天服务. 从这里开 ...
- Linux IO时事检测工具iostat
Linux IO时事检测工具iostat iostat命令用于检测linux系统io设备的负载情况,运行iostat将显示自上次运行该命令以后的统计信息.用户可以通过指定统计的次数和时间来获得所需的统 ...
随机推荐
- telnet如何保存输出内容到本地
telnet如何保存输出内容到本地 http://bbs.csdn.net/topics/391023327 一种将程序的标准输出重定向到telnet终端的方法 http://blog.chinaun ...
- C基础 常用设计模式粗解
引言 面向对象, 设计模式是现代软件开发基石. C的面向过程已经很简洁, 但不代表C就没有面向对象.(libuv框架中C面向对象用的很多) 因为思想是互通的.全当熟悉一下那些常用的设计模式.先假定有一 ...
- caffe Python API 之 数据输入层(Data,ImageData,HDF5Data)
import sys sys.path.append('/projects/caffe-ssd/python') import caffe4 net = caffe.NetSpec() 一.Image ...
- 经典卷积网络模型 — VGGNet模型笔记
一.简介 VGGNet是计算机视觉组(Visual Geometry Group)和Google DeepMind公司的研究员一起研究的深度卷积神经网络.VGGNet探索了卷积神经网络深度与性能之间的 ...
- PCA和SVD
一.PCA(Principal Component Analysis) 主成分分析,数据从原来的坐标系转换到新的坐标系,只保留新坐标系中的前面几个坐标轴,即对数据进行了降维处理 1.算法描述 (1)第 ...
- Activiti如何替换已部署流程图
首先交代下背景:我们有一个已经上线的activiti工作流系统,对于流程图的操作已经封装好部署,查看,删除的接口.此时客户提出要修改个别流程图里的节点名称. 我的第一个想法就是本地修改流程图bpmn文 ...
- window.screen.height和window.screen.availHeight和document.body.clientHeight和document.documentElement.clientHeight
说这几个属性前 我说一下我的设备 我的设备有两个,一个高度为1080的显示器,一个高度为800的电脑 第一种:window.screen.height 这个方法是获取用户电脑屏幕的高度,是不关浏览器或 ...
- C# 实现动态添加列,新增合计行,求和
DataTable da = CommonBLL.GetList("*", "sys_dict", "IfState=1 and DictTypeId ...
- hdu 2955(概率转化,01背包)
Hot~~招聘——巴卡斯(杭州),壹晨仟阳(杭州),英雄互娱(杭州) (包括2016级新生)除了校赛,还有什么途径可以申请加入ACM校队? Robberies Time Limit: 2000/100 ...
- JAVA版数据库主键ID生成器
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public clas ...