1、t-io是神马?
<dependency> <groupId>org.t-io</groupId> <artifactId>tio-core</artifactId> <version>3.0.2.v20180612-RELEASE</version> </dependency>
② TioServer
不知道要用什么,就先造一个TioServer,它就会告诉接下来该干什么。
TioServer tioServer = new TioServer(serverGroupContext);
需要一个ServerGroupContext。还是老样子,造一个ServerGroupContext,就知道接下来的步骤。
ServerGroupContext serverGroupContext = new ServerGroupContext("tio-server", new ServerAioHandler(), new ServerAioListener());
需要一个字符串String,表示的是服务端的名称。之后是ServerAioHandler和ServerAioListener,这两个是接口,需要自己实现。
先是ServerAioHandler的实现类,看其中的方法就知道是用来编码和解码,还有就是处理业务逻辑(handler方法)
package com.xxjsll.server.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tio.core.ChannelContext; import org.tio.core.GroupContext; import org.tio.core.Node; import org.tio.core.Tio; import org.tio.core.exception.AioDecodeException; import org.tio.core.intf.Packet; import org.tio.server.intf.ServerAioHandler; import java.nio.ByteBuffer; /** * @author tsinghua * @date 2018/6/20 */ public class MServerAioHandler implements ServerAioHandler { private static final Logger logger = LoggerFactory.getLogger(MServerAioHandler.class); public Packet decode(ByteBuffer byteBuffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException { logger.debug("inside decode..."); if (readableLength < ServerPacket.PACKET_HEADER_LENGTH) { return null; } int bodyLength = byteBuffer.getInt(); if (bodyLength < 0) { throw new AioDecodeException("body length[" + bodyLength + "] is invalid. romote: " + channelContext.getServerNode()); } int len = bodyLength + ServerPacket.PACKET_HEADER_LENGTH; if (len > readableLength) { return null; } else { byte[] bytes = new byte[len]; int i = 0; while(true){ if(byteBuffer.remaining() == 0){ break; } byte b = byteBuffer.get(); bytes[i++] = b; } ServerPacket serverPacket = new ServerPacket(); serverPacket.setBody(bytes); return serverPacket; } } public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) { logger.info("inside encode..."); ServerPacket serverPacket = (ServerPacket) packet; byte[] body = serverPacket.getBody(); int bodyLength = 0; if(body != null){ bodyLength = body.length; } ByteBuffer byteBuffer = ByteBuffer.allocate(bodyLength + ServerPacket.PACKET_HEADER_LENGTH); byteBuffer.order(groupContext.getByteOrder()); byteBuffer.putInt(bodyLength); if (body != null) { byteBuffer.put(body); } return byteBuffer; } public void handler(Packet packet, ChannelContext channelContext) throws Exception { logger.debug("inside handler..."); channelContext.setServerNode(new Node("127.0.0.1", ServerPacket.PORT)); ServerPacket serverPacket = (ServerPacket) packet; byte[] body = serverPacket.getBody(); if(body != null){ String bodyStr = new String(body, "utf-8"); ServerPacket serverPacket1 = new ServerPacket(); serverPacket1.setBody(("receive from ["+ channelContext.getClientNode() + "]: " + bodyStr).getBytes("utf-8")); Tio.send(channelContext, serverPacket1); } } }
接着就是ServerAioListener的实现类,是个监听类。可以很容易知道其中每一个方法的作用。
package com.xxjsll.server.util; import org.tio.core.ChannelContext; import org.tio.core.intf.Packet; import org.tio.server.intf.ServerAioListener; /** * @author tsinghua * @date 2018/6/20 */ public class MServerAioListener implements ServerAioListener { public void onAfterConnected(ChannelContext channelContext, boolean b, boolean b1) throws Exception { } public void onAfterDecoded(ChannelContext channelContext, Packet packet, int i) throws Exception { } public void onAfterReceivedBytes(ChannelContext channelContext, int i) throws Exception { } public void onAfterSent(ChannelContext channelContext, Packet packet, boolean b) throws Exception { } public void onAfterHandled(ChannelContext channelContext, Packet packet, long l) throws Exception { } public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String s, boolean b) throws Exception { } }
在ServerAioHandler的实现类和ServerAioListener的实现类中,有出现一个Packet类,这就是携带数据的类,需要通过继承来打造自己的类。
package com.xxjsll.server.util; import org.tio.core.intf.Packet; /** * @author tsinghua * @date 2018/6/20 */ public class ServerPacket extends Packet { public static final Integer PACKET_HEADER_LENGTH = 4; public static final Integer PORT = 8999; byte[] body;//数据 public byte[] getBody() { return body; } public void setBody(byte[] body) { this.body = body; } }
至此,服务端基本完成了,现在就剩下启动。
package com.xxjsll.server; import com.xxjsll.server.util.MServerAioHandler; import com.xxjsll.server.util.MServerAioListener; import org.tio.server.ServerGroupContext; import org.tio.server.TioServer; import java.io.IOException; /** * @author tsinghua * @date 2018/6/20 */ public class TIOServer { public static void main(String[] args) throws IOException { ServerGroupContext serverGroupContext = new ServerGroupContext("tio-server", new MServerAioHandler(), new MServerAioListener()); TioServer server = new TioServer(serverGroupContext); TioServer tioServer = new TioServer(serverGroupContext); server.start("127.0.0.1", 8999); } }
服务端完成。
③ 接着就是客户端,其实和服务端差不多。
ClientAioHandler和ClientAioListener两个接口,还有一个Packet,和服务端差不多。
- ClientAioHandler的实现类。
package com.xxjsll.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 java.nio.ByteBuffer; /** * @author tsinghua * @date 2018/6/20 */ public class MClientAioHander implements ClientAioHandler { Logger logger = LoggerFactory.getLogger(MClientAioHander.class); @Override public Packet heartbeatPacket() { return new ClientPacket(); } @Override public Packet decode(ByteBuffer byteBuffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException { if(readableLength < ClientPacket.PACKET_HEADER_LENGTH){ return null; } int bodyLength = byteBuffer.getInt(); if(bodyLength < 0){ throw new AioDecodeException("body length is invalid.romote: " + channelContext.getServerNode()); } int usefulLength = ClientPacket.PACKET_HEADER_LENGTH + bodyLength; if(usefulLength > readableLength){ return null; }else { ClientPacket packet = new ClientPacket(); byte[] body = new byte[bodyLength]; byteBuffer.get(body); packet.setBody(body); return packet; } } @Override public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) { ClientPacket clientPacket = (ClientPacket) packet; byte[] body = clientPacket.getBody(); int bodyLength = 0; if(body != null){ bodyLength = body.length; } int len = ClientPacket.PACKET_HEADER_LENGTH + bodyLength; ByteBuffer byteBuffer = ByteBuffer.allocate(len); byteBuffer.order(groupContext.getByteOrder()); byteBuffer.putInt(bodyLength); if(body != null){ byteBuffer.put(body); } return byteBuffer; } @Override public void handler(Packet packet, ChannelContext channelContext) throws Exception { ClientPacket clientPacket = (ClientPacket) packet; byte[] body = clientPacket.getBody(); if(body != null){ String bodyStr = new String(body, "utf-8"); logger.debug("客户端收到消息: " + bodyStr); } } }
- ClientAioListener的实现类
package com.xxjsll.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tio.client.intf.ClientAioListener; import org.tio.core.ChannelContext; import org.tio.core.Tio; import org.tio.core.intf.Packet; /** * @author tsinghua * @date 2018/6/20 */ public class MClientAioListener implements ClientAioListener { Logger logger = LoggerFactory.getLogger(MClientAioListener.class); private static Integer count = 0; @Override public void onAfterConnected(ChannelContext channelContext, boolean b, boolean b1) throws Exception { logger.info("onAfterConnected!"); } @Override public void onAfterDecoded(ChannelContext channelContext, Packet packet, int i) throws Exception { logger.info("onAfterDecoded..."); } @Override public void onAfterReceivedBytes(ChannelContext channelContext, int i) throws Exception { logger.info("onAfterReceivedBytes-------------------" + i); } @Override public void onAfterSent(ChannelContext channelContext, Packet packet, boolean b) throws Exception { logger.info("onAfterSent..."); } @Override public void onAfterHandled(ChannelContext channelContext, Packet packet, long l) throws Exception { System.out.println("onAfterHandled..."); ClientPacket clientPacket = (ClientPacket) packet; String resData = new String(clientPacket.getBody(), "utf-8"); logger.info("[" + channelContext.getServerNode() + "]: " + resData); count++; ((ClientPacket) packet).setBody(("[" + channelContext.getServerNode() + "]: " + count).getBytes()); Thread.sleep(5000); Tio.send(channelContext, packet); } @Override public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String s, boolean b) throws Exception { logger.error(throwable.getMessage()); logger.info(s); } }
- Packet
package com.xxjsll.util; import org.tio.core.intf.Packet; /** * @author tsinghua * @date 2018/6/20 */ public class ClientPacket extends Packet { public static final Integer PACKET_HEADER_LENGTH = 4; private byte[] body; public byte[] getBody() { return body; } public void setBody(byte[] body) { this.body = body; } }
接着就是向服务端发送连接请求,至于处理服务端的回复则是在ClientAioListener的实现类中。
package com.xxjsll; import com.xxjsll.util.ClientPacket; import com.xxjsll.util.MClientAioHander; import com.xxjsll.util.MClientAioListener; import org.tio.client.ClientChannelContext; import org.tio.client.ClientGroupContext; import org.tio.client.TioClient; import org.tio.core.Node; import org.tio.core.Tio; /** * Hello world! * */ public class App { public static void main( String[] args ) throws Exception { ClientGroupContext clientGroupContext = new ClientGroupContext(new MClientAioHander(), new MClientAioListener()); TioClient tioClient = new TioClient(clientGroupContext); ClientChannelContext clientChannelContext = tioClient.connect(new Node("127.0.0.1", 8999)); ClientPacket clientPacket = new ClientPacket(); clientPacket.setBody("hello,t-tio".getBytes("utf-8")); Tio.send(clientChannelContext, clientPacket); } }④ 总结一下:这只是初步运用,算个helloworld。
文章来源: t-io初学