基于t-io的MI工具实现

Posted shihaiming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于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工具实现的主要内容,如果未能解决你的问题,请参考以下文章

网络编程框架t-io的编程基本知识介绍

通讯框架 T-io 学习——给初学者的Demo:ShowCase设计分析

十年磨一剑,匠心打造中国人自己的网络编程架构t-io

(转)开源项目t-io

通讯框架 t-io 学习——websocket 部分源码解析

从零一起学Spring Boot之LayIM项目长成记websocket