C#异步服务器套接字-线程安全/性能(MMO游戏)
我正在为我的2D MMO小游戏编写这个游戏服务器 下面是我的问题:C#异步服务器套接字-线程安全/性能(MMO游戏),c#,.net,multithreading,asynchronous,asyncsocket,C#,.net,Multithreading,Asynchronous,Asyncsocket,我正在为我的2D MMO小游戏编写这个游戏服务器 下面是我的问题: 您如何看待代码的线程安全性? 你能告诉我问题在哪里以及如何修复/修补它们吗 这是我的密码: using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Collections.Generic; using System.Data; using System.Dat
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
public class Constanti
{
public const int CLASS_DARKELF_MAGICIAN = 1;
public const int CLASS_HUMAN_MAGICIAN = 2;
public const int CLASS_WARRIOR = 3;
public const int CLASS_MODERN_GUNMAN = 4;
public const int SUIT_1 = 1;
public const int SUIT_2 = 2;
public const int SUIT_3 = 3;
public const int SUIT_4 = 4;
public const int SUIT_Admin = 5;
//MAX/MIN
public const int MAX_LEVEL = 100;
public const int MAX_SKILL_LEVEL = 1000;
//SERVER MAX/MIN
public const int MAX_CONNECTIONS = 300;
public const int MAX_CONNECTIONS_IP = 4;
}
// State object for reading client data asynchronously
public class Player
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
//Player-Info
public int PlayerStats_Health = 0;
public int PlayerStats_Energy = 0;
public int PlayerInfo_Class = 0;
public int PlayerInfo_Suit = 0;
public int PlayerInfo_Level = 0;
public int PlayerInfo_SkillLevel = 0;
public void SetDefaults()
{
PlayerStats_Health = 100;
PlayerStats_Energy = 200;
PlayerInfo_Class = Constanti.CLASS_DARKELF_MAGICIAN;
PlayerInfo_Suit = Constanti.SUIT_1;
PlayerInfo_Level = 1;
PlayerInfo_SkillLevel = 1;
}
public Player()
{
}
public String pIPAddress;
}
public class GameObjectLists
{
public static List<Player> PlayersList = new List<Player>();
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public static int PlayersOnline = 0;
public AsynchronousSocketListener()
{}
public static void InitializeMySQL()
{
//TODO MySQLI/MySQL Connection
}
public static void MysqlUpdateQuery()
{
//Mysql UPDATE, no return stmt
}
public static String MySQLSelect()
{
//TODO MySQL Select
String retdata="test";
return retdata;
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
/*
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];*/
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 86);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(50);
Console.WriteLine("Server Started, waiting for connections...");
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
//Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket clientsocket = listener.EndAccept(ar);
// Signal the main thread to continue.
allDone.Set();
clientsocket.Blocking = false; //set to non-blocking
// Create the state object.
Player PlayerInfo = new Player();
PlayerInfo.workSocket = clientsocket;
IPEndPoint thisIpEndPoint = PlayerInfo.workSocket.RemoteEndPoint as IPEndPoint; //Get Local Ip Address
PlayerInfo.pIPAddress = thisIpEndPoint.Address.ToString();
GameObjectLists.PlayersList.Add(PlayerInfo);
PlayersOnline++;
int numconnsofip = 0;
GameObjectLists.PlayersList.ForEach(delegate(Player PlayerInfoCheck)
{
//Console.WriteLine(name);
if (PlayerInfoCheck.pIPAddress == PlayerInfo.pIPAddress)
{
numconnsofip++;
}
});
if (PlayersOnline > Constanti.MAX_CONNECTIONS || numconnsofip > Constanti.MAX_CONNECTIONS_IP)
{
Disconnect(clientsocket, PlayerInfo);
}
else
{
Console.WriteLine("Player with IP:[{0}] has [{1}] Connections", thisIpEndPoint.Address.ToString(), numconnsofip);
PlayerInfo.SetDefaults();
//clientsocket.LingerState = new LingerOption(true, 2); // give it up to 2 seconds for send
Console.WriteLine("New Connection Total:[{0}]", PlayersOnline);
clientsocket.BeginReceive(PlayerInfo.buffer, 0, Player.BufferSize, 0, new AsyncCallback(ReadCallback),
PlayerInfo);
}
}
public static void ProtocolCore(Player PlayerInfo, String data)
{
Console.WriteLine("Procesing Packet:{0}",data);
//if data == bla bla then send something to everyone:
GameObjectLists.PlayersList.ForEach(delegate(Player ObjPlayerInfo)
{
Send(data,ObjPlayerInfo);
});
}
public static void ReadCallback(IAsyncResult ar)
{
// TEST #1 - IF WE HANG HERE, THERE WILL BE STILL OTHER CONNECTIONS COMING HERE, BUT NO MULTI THREADING??
// Retrieve the state object and the clientsocket socket
// from the asynchronous state object.
Player PlayerInfo = (Player)ar.AsyncState;
Socket clientsocket = PlayerInfo.workSocket;
try
{
String content = String.Empty; //content buffer
// Read data from the client socket.
// IF THIS FAILS, WE CATCH / ASSUMING THAT:
// THE CLIENT FORCE-CLOSED THE CONNECTION OR OTHER REASON.
int bytesRead = clientsocket.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
PlayerInfo.sb.Append(Encoding.ASCII.GetString(
PlayerInfo.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = PlayerInfo.sb.ToString();
int eofindex = content.IndexOf("<EOF>");
if (eofindex > -1)
{
// All the data has been read from the
// client. Display it on the console.
content = content.Substring(0,eofindex); //remove THE <EOF>
Console.WriteLine("Read {0} bytes from socket. Data : {1}",content.Length, content);
//PROCESS THE PACKET/DATA (PROTOCOL CORE)
ProtocolCore(PlayerInfo, content);
//Echo the data back to the client.
Send(content, PlayerInfo);
// CLEAR THE BUFFERS
PlayerInfo.sb.Remove(0, PlayerInfo.sb.Length);
Array.Clear(PlayerInfo.buffer, 0, PlayerInfo.buffer.Length);
// GO TO LISTEN FOR NEW DATA
clientsocket.BeginReceive(PlayerInfo.buffer, 0, Player.BufferSize, 0,
new AsyncCallback(ReadCallback), PlayerInfo);
}
else
{
// Not all data received. Get more.
clientsocket.BeginReceive(PlayerInfo.buffer, 0, Player.BufferSize, 0,
new AsyncCallback(ReadCallback), PlayerInfo);
}
}
else
{
//ASSUMING WE RECEIVED 0 SIZED PACKET or CLIENT DISCONNECT / THEREFORE CLOSE THE CONNECTION
Disconnect(clientsocket, PlayerInfo);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Disconnect(clientsocket, PlayerInfo);
}
}
private static void Send(String data,Player PlayerInfo)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
PlayerInfo.workSocket.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), PlayerInfo);
}
private static void Disconnect(Socket clientsocket, Player PlayerInfo)
{
try
{
PlayersOnline--; //Is this Thread-Safe also?
GameObjectLists.PlayersList.Remove(PlayerInfo);
Console.WriteLine("Socket Disconnected, PlayerObjects:[{0}]", GameObjectLists.PlayersList.Count);
clientsocket.Shutdown(SocketShutdown.Both);
clientsocket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void SendCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Player PlayerInfo = (Player)ar.AsyncState;
Socket clientsocket = PlayerInfo.workSocket;
try
{
// Complete sending the data to the remote device.
int bytesSent = clientsocket.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Disconnect(clientsocket, PlayerInfo);
}
}
public static int Main(String[] args)
{
InitializeMySQL();
StartListening();
return 0;
}
}
使用系统;
Net系统;
使用System.Net.Sockets;
使用系统文本;
使用系统线程;
使用System.Collections.Generic;
使用系统数据;
使用System.Data.SqlClient;
使用System.Data.SqlTypes;
君士坦提公务舱
{
公共const int CLASS_DARKELF_魔术师=1;
公共常数int CLASS_HUMAN_魔术师=2;
公共const int CLASS_WARRIOR=3;
公共建筑国际级现代枪手=4;
公营建筑1=1;
公共建筑国际诉讼2=2;
公营建筑3=3;
公营建筑4=4;
公共建筑内部行政=5;
//最大/分钟
公共常数int MAX_LEVEL=100;
公共建筑最大技能水平=1000;
//服务器最大/分钟
公共const int MAX_CONNECTIONS=300;
公共const int MAX_CONNECTIONS_IP=4;
}
//用于异步读取客户端数据的状态对象
公开课选手
{
//客户端套接字。
公共套接字工作组=null;
//接收缓冲区的大小。
public const int BufferSize=1024;
//接收缓冲区。
公共字节[]缓冲区=新字节[BufferSize];
//接收到的数据字符串。
公共StringBuilder sb=新StringBuilder();
//玩家信息
public int PlayerStats_Health=0;
公共int PlayerStats_Energy=0;
public int PlayerInfo_Class=0;
公共int PlayerInfo_Suit=0;
公共int PlayerInfo_级别=0;
public int PlayerInfo_SkillLevel=0;
公共void SetDefaults()
{
PlayerStats_Health=100;
玩家状态能量=200;
PlayerInfo_Class=Constanti.Class_DARKELF_魔术师;
PlayerInfo_Suit=Constanti.Suit_1;
PlayerInfo_Level=1;
PlayerInfo_SkillLevel=1;
}
公共玩家()
{
}
公共字符串地址;
}
公共类游戏对象列表
{
public static List PlayersList=new List();
}
公共类异步SocketListener
{
//线程信号。
public static ManualResetEvent allDone=新的ManualResetEvent(false);
公共静态int PlayersOnline=0;
公共异步SocketListener()
{}
publicstaticvoid初始值为emysql()
{
//TODO MySQLI/MySQL连接
}
公共静态void MysqlUpdateQuery()
{
//Mysql更新,不返回stmt
}
公共静态字符串MySQLSelect()
{
//TODO MySQL选择
字符串retdata=“test”;
返回数据;
}
公共静态侦听()
{
//输入数据的数据缓冲区。
字节[]字节=新字节[1024];
//为套接字建立本地端点。
//计算机的DNS名称
/*
IPHostEntry ipHostInfo=Dns.Resolve(Dns.GetHostName());
IPAddress IPAddress=ipHostInfo.AddressList[0]*/
IPEndPoint localEndPoint=新的IPEndPoint(IPAddress.Any,86);
//创建TCP/IP套接字。
套接字侦听器=新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.Tcp);
//将套接字绑定到本地端点并侦听传入连接。
尝试
{
Bind(localEndPoint);
听(50);
WriteLine(“服务器已启动,正在等待连接…”);
while(true)
{
//将事件设置为非信号状态。
全部完成。重置();
//启动异步套接字以侦听连接。
listener.beginacept(
新建异步回调(AcceptCallback),
听众);
//等待连接完成后再继续。
全部完成。WaitOne();
}
}
捕获(例外e)
{
Console.WriteLine(如ToString());
}
//Console.WriteLine(“\n按ENTER继续…”);
Console.Read();
}
公共静态无效接受回调(IAsyncResult ar)
{
//获取处理客户端请求的套接字。
套接字侦听器=(套接字)ar.AsyncState;
套接字clientsocket=listener.EndAccept(ar);
//向主线程发出继续的信号。
allDone.Set();
clientsocket.Blocking=false;//设置为非阻塞
//创建状态对象。
Player PlayerInfo=新玩家();
PlayerInfo.workSocket=客户端套接字;
IPEndPoint thisIpEndPoint=PlayerInfo.workSocket.RemoteEndPoint作为IPEndPoint;//获取本地Ip地址
PlayerInfo.pIPAddress=thisIpEndPoint.Address.ToString();
GameObjectList.PlayerList.Add(PlayerInfo);
PlayerOnline++;
int numconnsofip=0;
GameObjectList.PlayerList.ForEach(代理(玩家PlayerInfoCheck)
{
//Console.WriteLine(名称);
if(PlayerInfoCheck.pIPAddress==PlayerInfo.pIPAddress)
{
numconnsofip++;
}
});
如果(playerOnline>Constanti.MAX|u CONNECTIONS | | numconnsofip>Constanti.MAX_CONNECTIONS|IP)
{
断开(客户端插座、播放器信息);
}
其他的
{
WriteLine(“具有IP:[{0}]的播放器有[{1}]个连接”,thisIpEndPoint.Address.ToString(),numconnsofip);
PlayerInfo.SetDefaults();
//clientsocket.LingerState=new LingerOption(true,2);//最多2秒用于发送
Console.WriteLine(“新连接总数:[{0}]”,PlayerOnline);
clientsocket.BeginReceive(PlayerInfo.buffer,0,Player.BufferSize,0,新异步回调(ReadCallback),
PlayerInfo);
}
}
公共静态无效协议(玩家PlayerI)