Skip to main content

服务器端编写

服务端代码

package org.tio.study.helloworld.server;

import java.nio.ByteBuffer;

import org.tio.core.Tio;
import org.tio.core.ChannelContext;
import org.tio.core.TioConfig;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;
import org.tio.study.helloworld.common.HelloPacket;
import org.tio.server.intf.ServerAioHandler;

/**
* @author tanyaowu
*/
public class HelloServerAioHandler implements ServerAioHandler {

/**
* 解码:把接收到的ByteBuffer,解码成应用可以识别的业务消息包
* 总的消息结构:消息头 + 消息体
* 消息头结构: 4个字节,存储消息体的长度
* 消息体结构: 对象的json串的byte[]
*/
@Override
public HelloPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException {
//提醒:buffer的开始位置并不一定是0,应用需要从buffer.position()开始读取数据
//收到的数据组不了业务包,则返回null以告诉框架数据不够
if (readableLength < HelloPacket.HEADER_LENGHT) {
return null;
}

//读取消息体的长度
int bodyLength = buffer.getInt();

//数据不正确,则抛出AioDecodeException异常
if (bodyLength < 0) {
throw new AioDecodeException("bodyLength [" + bodyLength + "] is not right, remote:" + channelContext.getClientNode());
}

//计算本次需要的数据长度
int neededLength = HelloPacket.HEADER_LENGHT + bodyLength;
//收到的数据是否足够组包
int isDataEnough = readableLength - neededLength;
// 不够消息体长度(剩下的buffe组不了消息体)
if (isDataEnough < 0) {
return null;
} else //组包成功
{
HelloPacket imPacket = new HelloPacket();
if (bodyLength > 0) {
byte[] dst = new byte[bodyLength];
buffer.get(dst);
imPacket.setBody(dst);
}
return imPacket;
}
}

/**
* 编码:把业务消息包编码为可以发送的ByteBuffer
* 总的消息结构:消息头 + 消息体
* 消息头结构: 4个字节,存储消息体的长度
* 消息体结构: 对象的json串的byte[]
*/
@Override
public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {
HelloPacket helloPacket = (HelloPacket) packet;
byte[] body = helloPacket.getBody();
int bodyLen = 0;
if (body != null) {
bodyLen = body.length;
}

//bytebuffer的总长度是 = 消息头的长度 + 消息体的长度
int allLen = HelloPacket.HEADER_LENGHT + bodyLen;
//创建一个新的bytebuffer
ByteBuffer buffer = ByteBuffer.allocate(allLen);
//设置字节序
buffer.order(tioConfig.getByteOrder());

//写入消息头----消息头的内容就是消息体的长度
buffer.putInt(bodyLen);

//写入消息体
if (body != null) {
buffer.put(body);
}
return buffer;
}


/**
* 处理消息
*/
@Override
public void handler(Packet packet, ChannelContext channelContext) throws Exception {
HelloPacket helloPacket = (HelloPacket) packet;
byte[] body = helloPacket.getBody();
if (body != null) {
String str = new String(body, HelloPacket.CHARSET);
System.out.println("收到消息:" + str);

HelloPacket resppacket = new HelloPacket();
resppacket.setBody(("收到了你的消息,你的消息是:" + str).getBytes(HelloPacket.CHARSET));
Tio.send(channelContext, resppacket);
}
return;
}
}

  • 服务器端启动类
package org.tio.study.helloworld.server;

import java.io.IOException;

import org.tio.study.helloworld.common.Const;
import org.tio.server.TioServer;
import org.tio.server.ServerTioConfig;
import org.tio.server.intf.ServerAioHandler;
import org.tio.server.intf.ServerAioListener;

/**
*
* @author tanyaowu
* 2017年4月4日 下午12:22:58
*/
public class HelloServerStarter {
//handler, 包括编码、解码、消息处理
public static ServerAioHandler aioHandler = new HelloServerAioHandler();

//事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口
public static ServerAioListener aioListener = null;

//一组连接共用的上下文对象
public static ServerTioConfig serverTioConfig = new ServerTioConfig("hello-tio-server", aioHandler, aioListener);

//tioServer对象
public static TioServer tioServer = new TioServer(serverTioConfig);

//有时候需要绑定ip,不需要则null
public static String serverIp = null;

//监听的端口
public static int serverPort = Const.PORT;

/**
* 启动程序入口
*/
public static void main(String[] args) throws IOException {
serverTioConfig.setHeartbeatTimeout(org.tio.study.helloworld.common.Const.TIMEOUT);

tioServer.start(serverIp, serverPort);
}
}