看了无数代码终于弄明白了游戏服务器的简单的原理-.-。
Socket代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace 游戏服务器
{
class Servers
{
private const int maxOL = 100;//最大连接数
private Connect[] connects = new Connect[maxOL];//连接池
private Socket serverSocket;
public Servers()
{
for(int i=0;i<maxOL;i++)
{
connects[i] = new Connect();
}
}
//创建客户端
public void start( string ip,int port)
{
//创建监听socket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定端口ip
IPAddress iPAddress = IPAddress.Parse(ip);
IPEndPoint ipEndPoint = new IPEndPoint(iPAddress, port);//获取端口号
serverSocket.Bind(ipEndPoint);
serverSocket.Listen(0);//表示可以无限制连接
serverSocket.BeginAccept(AcceptCallBack, null);//开始监听
OutPut.put("服务端", "服务端创建成功");
}
private void AcceptCallBack(IAsyncResult ar)
{
try
{
Socket clienSocket = serverSocket.EndAccept(ar);//停止接受
int index = getIndex();
Console.Write("开始执行"+index);
if (index==-1)
{
clienSocket.Close();
Console.WriteLine("以达到最大连接数");
}
else
{
Connect connect = connects[index];
connect.Init(clienSocket);//初始化该conn
OutPut.put("服务端", "有新的连接:" + connect.getIP());
//开始异步接受消息
//存储位置,开始位置,最大数量,不适用,让哪个方法处理(定义一个事件方法),传递的数据(为了在下面调用它,把他当作参数传递)
connect.socket.BeginReceive(connect.msgBuffer, connect.firstPOS, connect.getBuffer(), SocketFlags.None, ReceiveCallBack, connect);
}
serverSocket.BeginAccept(AcceptCallBack, null);
}
catch
{
}
}
private void ReceiveCallBack(IAsyncResult ar)
{
Connect conn = (Connect)ar.AsyncState;
try
{
int count = conn.socket.EndReceive(ar);//判断接受了多少个字节
if(count<=0)
{
OutPut.put("服务端", "接受数据异常(001),断开连接");
conn.socket.Close();
conn.Resert();//重置连接池里面的对象
return;
}
//处理数据包
conn.firstPOS += count;//写入消息的长度
Message.analyzeMsg(conn);
//再次调用接受消息
conn.socket.BeginReceive(conn.msgBuffer, conn.firstPOS, conn.getBuffer(), SocketFlags.None, ReceiveCallBack, conn);
}
catch(Exception e)
{
OutPut.put("服务端" , "接受数据异常(002),断开连接");
conn.socket.Close();
conn.Resert();
}
}
private int getIndex()//返回连接池中没有被使用的对象的下标
{
for (int i = 0; i < maxOL; i++)
{
//如果没有被使用
if (!connects[i].isUsed)
{
return i;
}
}
return -1;
}
}
}
错误信息处理:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 游戏服务器
{
class OutPut
{
public static void put(string a,string b)
{
Console.WriteLine("[" + a + "]" + "....." + b);
}
}
}
Connect代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
namespace 游戏服务器
{
class Connect
{
public bool isUsed=false;//是否被使用
public Socket socket;
private const int MAX_msg_Size = 2048;//缓冲区大小
public byte[] msgBuffer = new byte[MAX_msg_Size];//缓冲区
public int firstPOS = 0;//第一个数据所在的位置
//初始化该conn
public void Init(Socket socket )
{
this.socket = socket;//赋值
this.isUsed = true;
}
public string getIP()//获取ip
{
if (!this.isUsed)
return "该连接没有被使用";
return socket.RemoteEndPoint.ToString();
}
public int getBuffer()
{
return MAX_msg_Size - firstPOS;
}
public void Resert()
{
socket = null;
firstPOS = 0;
isUsed = false;
}
}
}
消息处理代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 游戏服务器
{
class Message
{
public static void analyzeMsg(Connect conn)//分析数据
{
if(conn.firstPOS<=4)//前四个字节是发送的长度信息,如果小于四说明信息不完整,不作处理
{
return;
}
//获取数据的大小
int count= BitConverter.ToInt32(conn.msgBuffer, 0);//自动获取四个字节的长度
if(conn.firstPOS-4>=count)//如果剩下的信息的长度减去了前四个字节,等于大于count所包含的说明正确
{
byte[] msg = new byte[count];
Array.Copy(conn.msgBuffer, 4, msg, 0, count);//把去掉头(消息长度)的数据发送单挑消息处理方法那里
msgDispatcher(conn, msg);//对单挑信息进行处理
int length = conn.firstPOS - count - 4;//剩余的长度
Array.Copy(conn.msgBuffer, 4 + count, conn.msgBuffer, 0, length);//去掉已经发送走的数据
analyzeMsg(conn);//再进行分析
}
}
public static void msgDispatcher(Connect conn,byte[] msg)
{
//消息的第一个参数是消息的类型,所以先获取消息类型的长度
int strLen;
//获取消息类型的长度
strLen= BitConverter.ToInt32(msg, 0);
//读取字符串
string name =System.Text.Encoding.UTF8.GetString(msg,4,strLen);
//以上获取了一条完整消息的类型
byte[] msgRemove = new byte[msg.Length - 4 - strLen];//除去了消息类型之外剩余消息的长度
Array.Copy(msg, 4 + strLen, msgRemove, 0, msgRemove.Length);
switch(name)
{
case "register"://注册
//把剩下消息发送给相应的方法
Console.WriteLine("注册信息");break;
case "login"://登录
Console.WriteLine("登录信息");break;
}
}
}
}
programm代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 游戏服务器
{
class Programm
{
static void Main(string[] args)
{
Servers server = new Servers();
server.start("127.0.0.1", 88); //启动服务端
string cmd;
while (true)
{
cmd = Console.ReadLine();
switch (cmd)
{
}
}
}
}
}