网络游戏服务器架构研究(-)代理服务器的简单实践

网络游戏的服务器框架中,通常需要代理服务器ProxyServer来解决高并发的请求。
目前实现了一个很简单代理服务器,没有考虑高并发的问题,只是实现了从客户端、代理服务器和游戏服务器的简单通信。
从客户端发送数据,经过代理服务器转发,到达游戏服务器
游戏服务器反射数据到代理服务器,后者在传递给客户端;

1. 负责接收来自客户端的消息
2. 负责转发来自服务器的消息
3. 管理客户端连接
   增加、删除客户端连接
   每个连接唯一标记
4. 管理服务器端连接
   根据serverid管理服务器端连接;

目前存在很多需要后续完善的地方
1. 客户端连接的管理,
       代理服务器接收到客户端连接后,产生随机的clientid, 构造出ClientConnectIon, 并且保存在map中待用
       目前的clientid是固定的
       所以目前还不支持多个客户端连接
       当然还涉及到客户端的断开的管理,从map中移除相关的连接;

2.   代理服务器的并发能力差
       后续考虑采用netty 或者mina来解决
       关键点是当客户端连接上来后,需要产生随机clientid, 保存到map中
       从游戏服务器下来的数据,能够找到正确clientid的客户端连接
       将数据传到正确的客户端中
       netty4.x的版本貌似比较复杂,和3.5的版本比较,多了很多新的类和接口,需要些时间来学习;

3.   数据包的封装
      一般都有数据包的封装,包头+包体;
      包头比较包括TAG,bodylen,cmdtype等

代理服务器先这样,后面的关于游戏服务器的框架更加重要;
package net.tuolian.main;

import net.tuolian.client.Client;
import net.tuolian.proxy.SocketProxy;
import net.tuolian.server.GameServer;

public class TestAll {
	
	public static void main(String[] args) {
		
		// boot game server
		new GameServer(8080);
		
		try {
			Thread.sleep(1000 * 3);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// boot socket proxy
		SocketProxy proxy = new SocketProxy(8081);
		proxy.connectToLogicServer("localhost", 8080);
		
		try {
			Thread.sleep(1000 * 3);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// start client
		new Client("localhost", 8081).doTest();
	}
}


package net.tuolian.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class GameServer implements Runnable{
	ServerSocket serverSocket 	= null;
	
	Logger logger = LogManager.getLogger(GameServer.class);

	public GameServer(int port)
	{
		try {
			serverSocket = new ServerSocket(port);
			
			logger.info("GameServer initialized");
			new Thread(this).start();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run()
	{
		while(true)
		{
			try {
				Socket socket = serverSocket.accept();
				
				logger.info("client accepted: " + socket.getRemoteSocketAddress());
				new MyClient(socket);
				
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}
	public void doTest()
	{
		new Thread(this).start();
	}
	
	class MyClient extends Thread
	{
		DataInputStream dis 		= null;
		DataOutputStream dos	 	= null;
		
		public MyClient(Socket socket)
		{
			try {
				dis = new DataInputStream(socket.getInputStream());
				dos = new DataOutputStream(socket.getOutputStream());
				start();
				
				logger.info("MyClient init");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}			
		}
		
		public void run()
		{
			while(true)
			{
				byte[] tmp =new byte[1024];
				try {
					if(dis.available()>0)
					{
						dis.read(tmp);
						logger.info("recv data from proxy len: " + new String(tmp));
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
//				int cmd = 1;
				try {
					dos.write("this is echo from gameserver: ".getBytes());
					dos.flush();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
		}
	}

}


package net.tuolian.proxy;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Random;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class SocketProxy implements Runnable{

	Logger logger = LogManager.getLogger(SocketProxy.class);
	ServerSocket sSocket = null;

	public SocketProxy(int port)
	{
		logger.info("SocketProxy init");
		try {
			sSocket = new ServerSocket(port);	
			
			new Thread(this).start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	public void run()
	{
		while(true)
		{
			Socket client = null;
			try {
				client = sSocket.accept();
				if(client!=null)
				{
					logger.info("accept client ");

					// new clientconn
					int clientId = new Random().nextInt();
					ClientConnection clientConn = new ClientConnection(this, clientId,client);
					addClientConn(clientConn, 1);
					
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public void connectToLogicServer(String ip, int port)
	{
		logger.info("connectToLogicServer");
		Socket socket;
		try {
			socket = new Socket(ip, port);
			
			ServerConnection serverConn =new ServerConnection(this, 1, socket);
			addServerConn(serverConn, 1);
			
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	private HashMap<Integer,ClientConnection> clientConns = new HashMap<Integer, ClientConnection>();
	private HashMap<Integer,ServerConnection> serverConns = new HashMap<Integer, ServerConnection>();

	public void addClientConn(ClientConnection clientConn, int clientId) {
		// TODO Auto-generated method stub
		clientConns.put(clientId, clientConn);
	}
	
	public ClientConnection getClientConn(int clientId)
	{
		return clientConns.get(clientId);
	}
	
	public void removeClientConn(int clientId)
	{
		clientConns.remove(clientId);
	}
	
	public void addServerConn(ServerConnection serverConn, int serverid) {
		// TODO Auto-generated method stub
		serverConns.put(serverid, serverConn);
	}
	
	public ServerConnection getServerConn(int serverid)
	{
		return serverConns.get(serverid);
	}
	
	public void removeServerConn(int serverId)
	{
		serverConns.remove(serverId);
	}
}


package net.tuolian.proxy;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class ClientConnection implements Runnable {
	
	Logger logger = LogManager.getLogger(ClientConnection.class);

	SocketProxy proxy = null;
	int clientId = 0;
	Socket client = null;
	DataInputStream dis = null;
	DataOutputStream dos = null;

	public ClientConnection(SocketProxy proxy, int clientId, Socket socket) {
		logger.info("ClientConnection init");
		this.proxy = proxy;
		this.clientId = clientId;
		this.client = socket;
		
		try {
			dis = new DataInputStream(socket.getInputStream());
			dos = new DataOutputStream(socket.getOutputStream());
			new Thread(this).start();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run()
	{
		while(true)
		{
			logger.info("run" );

			try {
				
				byte[] rawData = new byte[1024];
				while(dis.available()>0)
				{
					logger.info("recv client data: " );

					dis.read(rawData);
					String msg = new String(rawData);
					logger.info(msg);

					int serverid = 1;
					ServerConnection severConn = proxy.getServerConn(serverid);
					if(severConn!=null)
					{
						severConn.sendData(rawData);
					}
				}
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public void sendDataBack(byte[] data)
	{
		logger.info(new String(data));

		try {
			dos.write(data);
			dos.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}


package net.tuolian.proxy;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class ServerConnection implements Runnable {

	Logger logger = LogManager.getLogger(ServerConnection.class);
	SocketProxy proxy = null;
	int serverId = 0;
	Socket client = null;
	DataInputStream dis = null;
	DataOutputStream dos = null;

	public ServerConnection(SocketProxy proxy, int serverId, Socket socket) {
		// TODO Auto-generated constructor stub
		logger.info("ServerConnection init");
		this.proxy = proxy;
		this.serverId = serverId;
		this.client = socket;
		
		try {
			dis = new DataInputStream(socket.getInputStream());
			dos = new DataOutputStream(socket.getOutputStream());
			
			new Thread(this).start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run()
	{
		while(true)
		{
			try {
				
				byte[] rawData = new byte[1024];
				while(dis.available()>0)
				{
					dis.read(rawData);
					
					logger.info(new String(rawData));
					// send to serverId;

					int clientId = 1;
					ClientConnection clientConn = proxy.getClientConn(clientId);
					if(clientConn!=null)
					{
						clientConn.sendDataBack(rawData);
					}
				}
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public void sendDataBack(byte[] data)
	{
		try {
			dos.write(data);
			dos.flush();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void sendData(byte[] data) {
		// TODO Auto-generated method stub
		try {
			dos.write(data);
			dos.flush();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

package net.tuolian.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class Client implements Runnable{

	Logger logger = LogManager.getLogger(Client.class);

	public Client()
	{
		
	}
	
	Socket socket = null;
	DataInputStream dis = null;
	DataOutputStream dos = null;
	
	public Client(String ip, int port)
	{
		try {
			socket = new Socket(ip, port);
			dis = new DataInputStream(socket.getInputStream());
			dos = new DataOutputStream(socket.getOutputStream());
			
			logger.info("connect to proxy server success");
			

		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void run()
	{
		while(true)
		{
			byte[] tmp =new byte[1024];
			try {
				if(dis.available()>0)
				{
					dis.read(tmp);
					logger.info(new String(tmp));
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			try {
				dos.write("hello from client ".getBytes());
				dos.flush();

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public void doTest()
	{
		new Thread(this).start();

	}
}

你可能感兴趣的:(游戏,框架,Mina)