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

网络游戏的服务器框架中,通常需要代理服务器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();

}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值