JAVA NIO 服务器(三)

开发准备:

上次介绍了NIO如何去写了一简单的服务器,没有实用性,真正自己要用到现实的需求中,会很麻烦,所以我们需要把一些关键的东西封装,如何去封装 

先参考下面框架图(这是我个人的理解,如有建议欢迎指出):


accept线程:用来接收连接,把接收到的玩家数据包,解包后,添加到消息队列。

wrok线程:用来处理玩家的请求,并把玩家请求让游戏服分发给相应的游戏模块,相应的模块处理后,返回处理结果.


session与数据包

session:把解包、封包、消息队列封装到session。

数据包:由包ID,包长度,包内容组成

分发:由work线程调用游戏服去处理。


代码示例

代码比较多,下面贴主要的代码:

Session:

package network.session;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import network.packet.Msg;

/**
 *
 * @author Jack Lei
 * @see readme.txt
 * @date 2016年1月18日 下午10:11:38
 */
public class GameSession implements ISession, ISessionId {
	private int				uid;
	private SocketChannel	channel;
	private ByteBuffer		reciveBuffer;
	private List<Msg>		reciveMsgList;
	private List<Msg>		writeMsgList;
	/**
	 * @param uid
	 */
	public GameSession(SocketChannel channel) {
		super();
		this.channel = channel;
		reciveBuffer = ByteBuffer.allocate(1024);
		reciveBuffer.order(ByteOrder.LITTLE_ENDIAN);
		reciveMsgList = new ArrayList<Msg>();
		writeMsgList = new ArrayList<Msg>();
	}

	public void registerId(int id) {
		this.uid = id;
	}

	public Iterator<Msg> iteratorReciveMsg() {
		return reciveMsgList.iterator();
	}

	public void clearReciveMsg() {
		reciveMsgList.clear();
	}

	/*
			(non-Javadoc)
	 * @see packge1.ISessionId#getSessionId()
	 */
	@Override
	public int getSessionId() {
		// TODO Auto-generated method stub
		return uid;
	}

	public void addWriteMsg(Msg msg) {
		writeMsgList.add(msg);
	}


	public void read() throws IOException {
		// TODO Auto-generated method stub
		int readCount = channel.read(reciveBuffer);
		if (readCount > 0) {
			reciveBuffer.flip();
			if (readCount >= Short.SIZE / 8) {
				short packetId = reciveBuffer.getShort();
				if (packetId > 0) {
					int size = reciveBuffer.getInt();
					byte[] body = new byte[size];
					reciveBuffer.get(body);
					reciveMsgList.add(new Msg(packetId, size, body));
					reciveBuffer.clear();
				}

			}
		}
	}

	/*
			(non-Javadoc)
	 * @see packge1.Session#write(java.nio.ByteBuffer)
	 */
	@Override
	public void write() throws IOException {
		// TODO Auto-generated method stub
		if (!writeMsgList.isEmpty()) {
			Iterator<Msg> iterator = writeMsgList.iterator();
			while (iterator.hasNext()) {
				Msg msg = iterator.next();
				ByteBuffer byteBuffer = ByteBuffer.allocate(msg.getMsgLen());
				byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
				byteBuffer.putShort(msg.getPacketId());
				byteBuffer.putInt(msg.getSize());
				byteBuffer.put(msg.getBody());
				byteBuffer.flip();
				channel.write(byteBuffer);
			}
			writeMsgList.clear();
		}
	}

}

数据包;

package network.packet;


/**
 *
 * @author Jack Lei
 * @see readme.txt
 * @date 2016年1月18日 下午9:58:17
 */
public class Msg {
	private short	packetId;
	private int		size;
	private byte[]	body	= new byte[0];

	/**
	 * @param packetId
	 * @param size
	 * @param body
	 */
	public Msg(short packetId, int size, byte[] body) {
		super();
		this.packetId = packetId;
		this.size = size;
		this.body = body;
	}


	/**
	 * @return the packetId
	 */
	public short getPacketId() {
		return packetId;
	}

	/**
	 * @param packetId
	 *            the packetId to set
	 */
	public void setPacketId(short packetId) {
		this.packetId = packetId;
	}

	/**
	 * @return the size
	 */
	public int getSize() {
		return size;
	}

	/**
	 * @param size
	 *            the size to set
	 */
	public void setSize(int size) {
		this.size = size;
	}

	/**
	 * @return the body
	 */
	public byte[] getBody() {
		return body;
	}

	/**
	 * @param body
	 *            the body to set
	 */
	public void setBody(byte[] body) {
		this.body = body;
	}

	public int getMsgLen() {
		return Short.SIZE / 8 + Integer.SIZE / 8 + body.length;
	}

}


游戏世界:

package network;

import java.util.logging.Logger;

import network.packet.Msg;
import network.packet.PacketId;
import network.session.GameSession;

/**
 *
 * @author Jack Lei
 * @see readme.txt
 * @date 2016年1月19日 下午4:50:35
 * @desc 
 */
public class GameWorld {
	private final static Logger	logger		= Logger.getLogger(GameWorld.class.getName());
	private static GameWorld	instance	= new GameWorld();

	private GameWorld() {

	}

	public static GameWorld getInstance() {
		return instance;
	}
	
	public void processNetMessage(GameSession session, Msg msg) {
		logger.info("recive data from client packetId = " + msg.getPacketId() + " size = " + msg.getSize());

		switch (msg.getPacketId()) {
		case PacketId.REQ_PLAYER_LOGIN:
			// 这里简单的做个示例,是用其他模块返回这个MSG
			String body = "登录成功";
			byte[] bytes = body.getBytes();
			Msg m = new Msg(PacketId.RESP_PLAYER_LOGIN, bytes.length, bytes);
			session.addWriteMsg(m);
			break;
		default:
			logger.info("error packetId.");
			break;
		}
	}
}


后续

服务端的就先写到这了,准备开始写客户端了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值