⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xynetsocket.cs

📁 网络游戏征服的服务端部分完整源码 VC编译 绝少的源码 有兴趣的可以
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using System.Threading;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using XYThreadPoolLib;

namespace XYNetSocketLib
{
	public delegate void ExceptionHandlerDelegate(Exception oBug, Socket sock);
	public delegate void ConnectionFilterDelegate(String sRemoteAddress, int nRemotePort, Socket sock);
	public delegate void BinaryInputHandlerDelegate(String sRemoteAddress, int nRemotePort, Byte[] pData);
	public delegate void StringInputHandlerDelegate(String sRemoteAddress, int nRemotePort, String sData);

	public class XYNetServer
	{
		private delegate void AcceptClientsDelegate();
		private delegate void DetectInputDelegate();
		private delegate void ProcessInputDelegate(Socket sock, IPEndPoint ipe);
		
		private const int m_nServerPause = 2;
		private const int m_nListenBacklog = 32;
		private const int m_nArrayCapacity = 512;
		private int m_nReadTimeout = 2;
		private int m_nMaxDataSize = 4*1024*1024;
		private int m_nMinThreadCount = 7;
		private int m_nMaxThreadCount = 12;
		private String m_sAddress = "";
		private int m_nPort = 0;
		private Socket m_socketServer = null;
		private XYThreadPool m_threadPool = new XYThreadPool();
		private Hashtable m_htSockets = new Hashtable(m_nArrayCapacity);
		private ArrayList m_listSockets = new ArrayList(m_nArrayCapacity);
		private ConnectionFilterDelegate m_delegateConnectionFilter = null;
		private ExceptionHandlerDelegate m_delegateExceptionHandler = null;
		private BinaryInputHandlerDelegate m_delegateBinaryInputHandler = null;
		private StringInputHandlerDelegate m_delegateStringInputHandler = null;
		private Exception m_exception = null;
		
		public XYNetServer(String sAddress, int nPort, int nMinThreadCount, int nMaxThreadCount)
		{
			if(sAddress!=null) m_sAddress = sAddress;
			if(nPort>0) m_nPort = nPort;
			if(nMinThreadCount>0) m_nMinThreadCount = nMinThreadCount+2;
			if(nMinThreadCount>0&&nMaxThreadCount>nMinThreadCount) m_nMaxThreadCount = nMaxThreadCount+2;
			else m_nMaxThreadCount = 2*(m_nMinThreadCount-2)+2;
		}

		~XYNetServer()
		{
			StopServer();
		}

		public Exception GetLastException()
		{
			Monitor.Enter(this);
			Exception exp = m_exception;
			Monitor.Exit(this);
			return exp;
		}

		public void StopServer()
		{
			try
			{
				Monitor.Enter(this);
				m_threadPool.StopThreadPool();
				if(m_socketServer!=null)
				{
					Socket sock = null;
					for(int i=0;i<m_listSockets.Count;i++)
					{
						sock = (Socket)(m_listSockets[i]);
						try
						{
							sock.Shutdown(SocketShutdown.Both);
							sock.Close();
						}
						catch(Exception) {}
					}
					try
					{
						m_socketServer.Shutdown(SocketShutdown.Both);
						m_socketServer.Close();
					}
					catch(Exception) {}
				}
			}
			catch(Exception) {}
			finally 
			{
				try
				{
					m_socketServer = null;
					m_htSockets.Clear();
					m_listSockets.Clear();
				}
				catch(Exception) {}
				Monitor.Exit(this); 
			}
		}

		public bool StartServer()
		{
			try
			{
				Monitor.Enter(this);
				XYNetCommon.SetSocketPermission();
				StopServer();
				m_threadPool.SetThreadErrorHandler(new ThreadErrorHandlerDelegate(ThreadErrorHandler));
				m_threadPool.StartThreadPool(m_nMinThreadCount, m_nMaxThreadCount);
				m_socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				m_socketServer.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
				IPEndPoint myEnd = (m_sAddress=="")?(new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], m_nPort)):(new IPEndPoint(IPAddress.Parse(m_sAddress), m_nPort));
				m_socketServer.Bind(myEnd);
				m_socketServer.Listen(m_nListenBacklog);
				m_threadPool.InsertWorkItem("Accept Clients", new AcceptClientsDelegate(AcceptClients), null, false);
				m_threadPool.InsertWorkItem("Detect Input", new DetectInputDelegate(DetectInput), null, false);
#if DEBUG
                Console.WriteLine("Server successfully started.");
#endif
				return true;
			}
			catch(Exception oBug) 
			{ 
				m_exception = oBug; 
				return false;
			}
			finally { Monitor.Exit(this); }
		}

		public void SetReadTimeout(int nReadTimeout)
		{
			Monitor.Enter(this);
			if(nReadTimeout>=5&&nReadTimeout<=1200) m_nReadTimeout = nReadTimeout;
			Monitor.Exit(this);
		}

		public void SetMaxDataSize(int nMaxDataSize)
		{
			Monitor.Enter(this);
			if(nMaxDataSize>=1024) m_nMaxDataSize = nMaxDataSize;
			Monitor.Exit(this);
		}

		public void SetConnectionFilter(ConnectionFilterDelegate pMethod)
		{
			Monitor.Enter(this);
			if(m_delegateConnectionFilter==null) m_delegateConnectionFilter = pMethod;
			Monitor.Exit(this);
		}

		public void SetExceptionHandler(ExceptionHandlerDelegate pMethod)
		{
			Monitor.Enter(this);
			if(m_delegateExceptionHandler==null) m_delegateExceptionHandler = pMethod;
			Monitor.Exit(this);
		}

		public void SetBinaryInputHandler(BinaryInputHandlerDelegate pMethod)
		{
			Monitor.Enter(this);
			if(m_delegateBinaryInputHandler==null) m_delegateBinaryInputHandler = pMethod;
			Monitor.Exit(this);
		}

		public Socket GetSocket(string IPAddress, int Port)
		{
			Monitor.Enter(this);
			Socket sock = (Socket)m_htSockets[IPAddress + ":" + Port];
			Monitor.Exit(this);
			return sock;
		}

		public void SetStringInputHandler(StringInputHandlerDelegate pMethod)
		{
			Monitor.Enter(this);
			if(m_delegateStringInputHandler==null) m_delegateStringInputHandler = pMethod;
			Monitor.Exit(this);
		}

		private void ThreadErrorHandler(ThreadPoolWorkItem oWorkItem, Exception oBug)
		{
			try
			{
				Monitor.Enter(this);
				if(m_delegateExceptionHandler!=null)
				{
					m_threadPool.InsertWorkItem("Handle Exception", m_delegateExceptionHandler, new Object[2]{oBug, null}, false);
				}
				else m_exception = oBug;
			}
			catch(Exception) { }
			finally { Monitor.Exit(this); }
		}

		public void DropClient(String sRemoteAddress, int nRemotePort)
		{
			Socket sock = null;
			try
			{
				Monitor.Enter(this);
				sock = (Socket) m_htSockets[sRemoteAddress + ":" + nRemotePort];
				m_htSockets.Remove(sRemoteAddress + ":" + nRemotePort);
				m_listSockets.Remove(sock);
			}
			catch (Exception)
			{}
			finally
			{
				Monitor.Exit(this);
			}
            if(sock!=null)
			{
				try
				{
					if (m_delegateExceptionHandler != null)
						m_delegateExceptionHandler.DynamicInvoke(new object[2]{new Exception("Client has been intentionally dropped by the server."), sock});
					sock.Shutdown(SocketShutdown.Both);
					sock.Close();
				}
				catch(Exception oBug) 
				{
					if(m_delegateExceptionHandler!=null)
					{
						m_threadPool.InsertWorkItem("Handle Exception", m_delegateExceptionHandler, new Object[2]{oBug, sock}, false);
					}
					else 
					{
				
						m_exception = oBug;
					}
				}
			}

		}

		private void AcceptClients()
		{
			while(true)
			{
				bool bHasNewClient = false;
				Socket sock = null;
				try
				{
					if(m_socketServer.Poll(m_nServerPause, SelectMode.SelectRead))
					{
						bHasNewClient = true;
						sock = m_socketServer.Accept();
						sock.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, 5000);
						IPEndPoint ipe = (IPEndPoint)(sock.RemoteEndPoint);
						if(m_delegateConnectionFilter!=null)
						{
							m_delegateConnectionFilter.DynamicInvoke(new Object[3]{ipe.Address.ToString(), ipe.Port, sock});
						}
						if(sock.Connected)
						{
							String sKey = ipe.Address.ToString() + ":" + ipe.Port.ToString();
							Monitor.Enter(this);
							if (m_htSockets.ContainsKey(sKey))  //Clean up a previous connection
							{
								Socket socketTemp = (Socket) m_htSockets[sKey];
								m_delegateExceptionHandler.DynamicInvoke(new Object[2]{new Exception("Connection already exists"), socketTemp});
								m_listSockets.Remove(socketTemp);
								m_htSockets.Remove(sKey);
							}						

							m_htSockets.Add(sKey, sock);
							m_listSockets.Add(sock);
							Monitor.Exit(this);
						}
					}
				}
				catch(Exception oBug)
				{
					if(sock!=null)
					{
						try
						{
							sock.Shutdown(SocketShutdown.Both);
							sock.Close();
						}
						catch(Exception) {}
					}
					if(m_delegateExceptionHandler!=null)
					{
						m_threadPool.InsertWorkItem("Handle Exception", m_delegateExceptionHandler, new Object[2]{oBug, sock}, false);
					}
					else 
					{
						Monitor.Enter(this);
						m_exception = oBug;
						Monitor.Exit(this);
					}
				}
				if(bHasNewClient) Thread.Sleep(m_nServerPause);
				else Thread.Sleep(10*m_nServerPause);
			}
		}

		private void DetectInput()
		{
			int nCounter = 0;
			while(true)
			{
				nCounter++;
				bool bNoData = true;
				try
				{
					for(int i=m_listSockets.Count-1;i>=0;i--)
					{
						Socket sock = null;
						IPEndPoint ipe = null;
						try
						{
							sock = (Socket)(m_listSockets[i]);
							ipe = (IPEndPoint)(sock.RemoteEndPoint);
							if(!sock.Connected) throw new Exception("Connection to client closed");
							//Removed: We dont want the net sockets to be sending funny ping packets to the conquer client
							//if(nCounter%1000==0) 
							//{
							//	if(sock.Send(new Byte[4]{2,0,0,0})!=4)
							//		throw new Exception("Failed to ping client socket");
							//}
							if(sock.Available>0)
							{
								Monitor.Enter(this);
								m_listSockets.RemoveAt(i);
								Monitor.Exit(this);
								bNoData = false;
								m_threadPool.InsertWorkItem("Process Input", new ProcessInputDelegate(ProcessInput), new Object[2] {sock, ipe}, false);
							}
						}
						catch(Exception oBug)
						{
							if(m_delegateExceptionHandler!=null)
							{
								m_delegateExceptionHandler.DynamicInvoke(new Object[2]{oBug, sock});
							}
							if(i>=0&&sock!=null)
							{
								Monitor.Enter(this);
								m_listSockets.RemoveAt(i);
								m_htSockets.Remove(ipe.Address.ToString() + ":" + ipe.Port.ToString());
								Monitor.Exit(this);
								try
								{
									sock.Shutdown(SocketShutdown.Both);
									sock.Close();
								}
								catch(Exception) {}
							}
							
						}
					}	
					if(bNoData) Thread.Sleep(2*m_nServerPause);
					else Thread.Sleep(m_nServerPause);
				}
				catch(Exception) {}
				finally
				{
					//Monitor.Exit(this);
				}
			}
		}

		private void ProcessInput(Socket sock, IPEndPoint ipe)
		{
			try
			{
				//Byte[] pHeader = new Byte[2];
				int nPos = 0;
				long nStart = DateTime.Now.Ticks;
				Byte [] pData = null;
				while(nPos<2)
				{
					if(sock.Available>0)
					{
						pData = new byte[sock.Available];
						nPos += sock.Receive(pData, nPos, sock.Available, SocketFlags.None);
						break;
//						if((pHeader[0]&0x000000FF)==255) 
//						{
//							sock.Shutdown(SocketShutdown.Both);
//							sock.Close();
//							Monitor.Enter(this);
//							m_htSockets.Remove(ipe.Address.ToString() + ":" + ipe.Port.ToString());
//							Monitor.Exit(this);
//							return;
//						}
					}
					else Thread.Sleep(m_nServerPause);
					if(nPos<2&&((DateTime.Now.Ticks-nStart)/10000)>m_nReadTimeout*1000) throw new Exception("Timeout while receiving incoming data");
				}
				//if((pHeader[0]&0x0000000F)!=2)
				//{
				//int nSize = pHeader[0] + pHeader[1]*256;// + pHeader[3]*65536+(pHeader[0]/16)*16777216;  Conquer only has 2 bytes for the size
				//if(nSize>m_nMaxDataSize) throw new Exception("Data size too large");
				//Byte[] pData = new Byte[nSize];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -