您的位置:首页 > 编程语言 > Java开发

JAVA NIO 服务器(三)

2016-01-20 15:07 459 查看

开发准备:

上次介绍了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;
}
}
}


后续

服务端的就先写到这了,准备开始写客户端了~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  NIO服务器