Mina封装好了很完善的方法,代码注释的很清楚直接上代码:
// 创建一个非阻塞的Server端socket,用NIO
IoAcceptor acceptor = new NioSocketAcceptor();
// 创建接受数据的过滤器, 处理最简单的字符串传输,Mina 已经为我们提供了 TextLineCodecFactory
// 编解码器工厂来对字符串进行编解码处理。
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
// 设定这个过滤器将一行一行的读取数据
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new SocketCodecFactory()));
// 然后我们把这个IoHandler 注册到IoService:
acceptor.setHandler(new TimeServerHandler());
// 设置读取数据的缓冲区大小
acceptor.getSessionConfig().setReadBufferSize(2048);
// 设置10没有消息就进入闲置状态
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
// 绑定端口号
acceptor.bind(new InetSocketAddress(Constant.PORT_NUMBER));
虽然Mina自己有自己的解码工厂,为了自己的也无需求一般我们会自己建立自己的解码工厂SocketCodecFactory()
public class SocketCodecFactory implements ProtocolCodecFactory {
private final SocketDecode decoder;
private final SocketEncode encoder;
public SocketCodecFactory() {
decoder = new SocketDecode();
encoder = new SocketEncode();
}
@Override
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}
@Override
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}
}
SocketDecode 这里处理自己的逻辑,根据客户端 发送的数据进行自己业务逻辑操作
public class SocketDecode implements ProtocolDecoder {
int bufid = 0;
@Override
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
int playerid = 0;
playerid = (int) session.getAttribute("PLAYERID", playerid);
if (playerid > 0) {
getStutasCode(in);
}
// 创建房间 并向客户端返回房间信息
if (bufid == 1) {
RoomManage.getInstace().create(playerid);
}
// 玩家进入房间 并向客户端返回所有玩家信息
if (bufid == 2) {
PBPlayer playerBuf = PBPlayer.parseFrom(in.array());
RoomManage.getInstace().enter(playerBuf.getRoomId(), new Player(playerBuf.getPlayerId(),
playerBuf.getName(), playerBuf.getHeadurl(), playerBuf.getGender(), playerBuf.getScore(), session));
}
// 玩家坐下
if (bufid == 3) {
PBPlayer playerBuf = PBPlayer.parseFrom(in.array());
PBSeat pbSeat = PBSeat.parseFrom(in.array());
RoomManage.getInstace().sitDown(
playerBuf.getRoomId(), new Player(playerBuf.getPlayerId(), playerBuf.getName(),
playerBuf.getHeadurl(), playerBuf.getGender(), playerBuf.getScore(), session),
pbSeat.getSeatId());
}
// 玩家离开房间 并向客户端返回此房间的所有信息
if (bufid == 3) {
PBPlayer playerBuf = PBPlayer.parseFrom(in.array());
RoomManage.getInstace().leave(playerBuf.getRoomId(), new Player(playerBuf.getPlayerId(), session));
}
// 开始游戏
if (bufid == 4) {
PBRoom pbroom = PBRoom.parseFrom(in.array());
RoomManage.getInstace().roomHashMap.get(pbroom.getRoomId()).begin();
}
}
private void getStutasCode(IoBuffer in) {
UtilsProtobuf.PButil buf = null;
try {
buf = UtilsProtobuf.PButil.parseFrom(in.array());
} catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bufid = buf.getCode();
}
@Override
public void dispose(IoSession session) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
// TODO Auto-generated method stub
}
}
里面的逻辑代码是我鞋的简单需求,以供以后查看便于阅读
SocketEncode 当服务端需要向客户端回复消息的时候回走到这个类(out.write(messsage))
public class SocketEncode implements ProtocolEncoder {
@Override
public void dispose(IoSession session) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
out.write(message);
}
}
客户端和服务端Mina基本相同
public class MimaTimeClient {
public static void main(String[] args) {
IoConnector connector = new NioSocketConnector();
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new PrefixedStringCodecFactory(Charset.forName("UTF-8"))));
connector.setHandler(new TimeClientHander());
ConnectFuture connectFuture = connector.connect(new InetSocketAddress("192.168.1.124", Constant.PORT_NUMBER));
// 等待建立连接
System.out.println("等待建立连接");
connectFuture.awaitUninterruptibly();
System.out.println("连接成功");
IoSession session = connectFuture.getSession();
PButil.Builder pbutils = PButil.newBuilder();
pbutils.setCode(1);
PButil info = pbutils.build();
byte[] result = info.toByteArray();
Scanner sc = new Scanner(System.in);
boolean quit = false;
while (!quit) {
String str = sc.next();
if (str.equalsIgnoreCase("quit")) {
quit = true;
}
session.write(result);
}
// 关闭
if (session != null) {
if (session.isConnected()) {
session.getCloseFuture().awaitUninterruptibly();
}
connector.dispose(true);
}
}
}
其中自定义的界面工厂和服务端相同我就不在重复上传了
PButil.Builder pbutils = PButil.newBuilder();
pbutils.setCode(1);
PButil info = pbutils.build();
byte[] result = info.toByteArray();
这里使用了protobuf用来传送数据,protobuf的使用在我博客中有