├── AsycServer ├── obj │ └── Debug │ │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ │ ├── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs │ │ ├── AsycServer.exe │ │ ├── AsycServer.pdb │ │ ├── AsycServer.csprojResolveAssemblyReference.cache │ │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ │ └── AsycServer.csproj.FileListAbsolute.txt ├── bin │ └── Debug │ │ ├── AsycServer.exe │ │ ├── AsycServer.pdb │ │ ├── AsycServer.vshost.exe │ │ ├── AsycServer.exe.config │ │ ├── AsycServer.vshost.exe.config │ │ └── AsycServer.vshost.exe.manifest ├── App.config ├── cProto.cs ├── CharData.cs ├── Properties │ └── AssemblyInfo.cs ├── Client.cs ├── AsycServer.csproj ├── MessageBuffer.cs ├── Program.cs └── AsyUdpServer.cs ├── AsycServer.v12.suo ├── README.md ├── .gitattributes ├── .gitignore └── AsycServer.sln /AsycServer/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AsycServer/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AsycServer/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AsycServer.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer.v12.suo -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsycServer 2 | 项目说明见博客http://blog.csdn.net/l_jinxiong/article/details/48917715 3 | -------------------------------------------------------------------------------- /AsycServer/bin/Debug/AsycServer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/bin/Debug/AsycServer.exe -------------------------------------------------------------------------------- /AsycServer/bin/Debug/AsycServer.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/bin/Debug/AsycServer.pdb -------------------------------------------------------------------------------- /AsycServer/obj/Debug/AsycServer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/obj/Debug/AsycServer.exe -------------------------------------------------------------------------------- /AsycServer/obj/Debug/AsycServer.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/obj/Debug/AsycServer.pdb -------------------------------------------------------------------------------- /AsycServer/bin/Debug/AsycServer.vshost.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/bin/Debug/AsycServer.vshost.exe -------------------------------------------------------------------------------- /AsycServer/obj/Debug/AsycServer.csprojResolveAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/obj/Debug/AsycServer.csprojResolveAssemblyReference.cache -------------------------------------------------------------------------------- /AsycServer/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caolaoyao/AsycServer/HEAD/AsycServer/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /AsycServer/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AsycServer/bin/Debug/AsycServer.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AsycServer/bin/Debug/AsycServer.vshost.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /AsycServer/cProto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AsycServer 8 | { 9 | public class cProto 10 | { 11 | public const int CONNECT = 100; 12 | public const int READY = 101; 13 | public const int SYNC_POS = 102; 14 | public const int SYNC_KEY = 103; 15 | public const int START = 104; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AsycServer/obj/Debug/AsycServer.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | D:\visual studio 2013\AsycServer\AsycServer\bin\Debug\AsycServer.exe.config 2 | D:\visual studio 2013\AsycServer\AsycServer\bin\Debug\AsycServer.exe 3 | D:\visual studio 2013\AsycServer\AsycServer\bin\Debug\AsycServer.pdb 4 | D:\visual studio 2013\AsycServer\AsycServer\obj\Debug\AsycServer.csprojResolveAssemblyReference.cache 5 | D:\visual studio 2013\AsycServer\AsycServer\obj\Debug\AsycServer.exe 6 | D:\visual studio 2013\AsycServer\AsycServer\obj\Debug\AsycServer.pdb 7 | -------------------------------------------------------------------------------- /AsycServer/bin/Debug/AsycServer.vshost.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /AsycServer/CharData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AsycServer 8 | { 9 | public class CharData 10 | { 11 | public int roleId; 12 | public string name; 13 | 14 | public CharData(string str) 15 | { 16 | string[] playStr = str.Split('#'); 17 | roleId = int.Parse(playStr[0]); 18 | name = playStr[1]; 19 | } 20 | 21 | public CharData(int roleId, string name) 22 | { 23 | this.roleId = roleId; 24 | this.name = name; 25 | } 26 | 27 | public override string ToString() 28 | { 29 | string str = roleId + "#" + name; 30 | return str; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AsycServer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsycServer", "AsycServer\AsycServer.csproj", "{56DDFAA5-EDAF-4882-997E-06783D471BC6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {56DDFAA5-EDAF-4882-997E-06783D471BC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {56DDFAA5-EDAF-4882-997E-06783D471BC6}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {56DDFAA5-EDAF-4882-997E-06783D471BC6}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {56DDFAA5-EDAF-4882-997E-06783D471BC6}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /AsycServer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("AsycServer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AsycServer")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("352f990c-d3e6-42dd-9abb-2d0c1c71f526")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /AsycServer/Client.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace AsycServer 12 | { 13 | public class Client 14 | { 15 | public int ID; 16 | public IPEndPoint tcpAdress, udpAdress; 17 | AsyUdpServer server; 18 | Socket socket; 19 | Stopwatch pingWatch; 20 | 21 | public bool Pinging 22 | { 23 | get 24 | { 25 | return pingWatch != null; 26 | } 27 | } 28 | 29 | public Client(int id, Socket sock, AsyUdpServer serv) 30 | { 31 | ID = id; 32 | server = serv; 33 | socket = sock; 34 | 35 | tcpAdress = (IPEndPoint)sock.RemoteEndPoint; 36 | Thread t = new Thread(AliveThread); 37 | t.Start(); 38 | } 39 | 40 | public void SendAcceptPoll() 41 | { 42 | socket.Send(BitConverter.GetBytes(ID)); 43 | } 44 | 45 | void AliveThread() 46 | { 47 | while (IsConnected() && server.Active) 48 | { 49 | Thread.Sleep(1000); 50 | } 51 | 52 | Disconnect(); 53 | } 54 | 55 | bool IsConnected() 56 | { 57 | try 58 | { 59 | if (udpAdress != null) socket.Send(new byte[] { 0 }); 60 | return true; 61 | } 62 | catch (SocketException e) 63 | { 64 | return false; 65 | } 66 | catch (Exception e) 67 | { 68 | server.CatchException(e); 69 | return false; 70 | } 71 | } 72 | 73 | public void Send(MessageBuffer msg) 74 | { 75 | server.Send(msg, this); 76 | } 77 | 78 | public void Disconnect() 79 | { 80 | if (socket == null) return; 81 | 82 | socket.Close(); 83 | socket = null; 84 | server.ClientDisconnected(this); 85 | } 86 | 87 | public void Ping() 88 | { 89 | if (Pinging) 90 | { 91 | server.PingResult(this, pingWatch.Elapsed.Milliseconds); 92 | pingWatch = null; 93 | } 94 | else 95 | { 96 | pingWatch = Stopwatch.StartNew(); 97 | server.Send(new MessageBuffer(new byte[] { AsyUdpServer.pingByte }), this); 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /AsycServer/AsycServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {56DDFAA5-EDAF-4882-997E-06783D471BC6} 8 | Exe 9 | Properties 10 | AsycServer 11 | AsycServer 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 63 | -------------------------------------------------------------------------------- /AsycServer/MessageBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AsycServer 8 | { 9 | public class MessageBuffer 10 | { 11 | List byteList = new List(); 12 | int cursor = 0; 13 | 14 | public byte[] Array 15 | { 16 | get 17 | { 18 | return byteList.ToArray(); 19 | } 20 | } 21 | 22 | public int Size 23 | { 24 | get 25 | { 26 | return byteList.Count; 27 | } 28 | } 29 | 30 | public MessageBuffer() 31 | { 32 | } 33 | 34 | public MessageBuffer(byte[] data) 35 | { 36 | byteList.AddRange(data); 37 | } 38 | 39 | public void MoveCursor(int n) 40 | { 41 | cursor += n; 42 | } 43 | public void Reset() 44 | { 45 | cursor = 0; 46 | } 47 | 48 | public byte ReadByte() 49 | { 50 | byte ret = byteList[cursor]; 51 | MoveCursor(1); 52 | 53 | return ret; 54 | } 55 | 56 | public short ReadShort() 57 | { 58 | short ret = BitConverter.ToInt16(byteList.ToArray(), cursor); 59 | MoveCursor(2); 60 | 61 | return ret; 62 | } 63 | 64 | public int ReadInt() 65 | { 66 | int ret = BitConverter.ToInt32(byteList.ToArray(), cursor); 67 | MoveCursor(4); 68 | 69 | return ret; 70 | } 71 | 72 | public float ReadFloat() 73 | { 74 | float ret = BitConverter.ToSingle(byteList.ToArray(), cursor); 75 | MoveCursor(4); 76 | 77 | return ret; 78 | } 79 | 80 | public double ReadDouble() 81 | { 82 | double ret = BitConverter.ToDouble(byteList.ToArray(), cursor); 83 | MoveCursor(8); 84 | 85 | return ret; 86 | } 87 | 88 | public string ReadString() 89 | { 90 | int len = ReadInt(); 91 | 92 | string s = ""; 93 | for (int i = 0; i < len; i++) 94 | s += (char)ReadByte(); 95 | 96 | return s; 97 | } 98 | 99 | public void WriteByte(short b) { WriteByte((byte)b); } 100 | public void WriteByte(int b) { WriteByte((byte)b); } 101 | public void WriteByte(byte b) 102 | { 103 | byteList.Add(b); 104 | } 105 | 106 | public void WriteShort(int s) { WriteShort((short)s); } 107 | public void WriteShort(short s) 108 | { 109 | byteList.AddRange(BitConverter.GetBytes(s)); 110 | } 111 | 112 | public void WriteInt(int i) 113 | { 114 | byteList.AddRange(BitConverter.GetBytes(i)); 115 | } 116 | 117 | public void WriteFloat(float f) 118 | { 119 | byteList.AddRange(BitConverter.GetBytes(f)); 120 | } 121 | 122 | public void WriteDouble(double d) 123 | { 124 | byteList.AddRange(BitConverter.GetBytes(d)); 125 | } 126 | 127 | public void WriteString(string s) 128 | { 129 | WriteInt(s.Length); 130 | for (int i = 0; i < s.Length; i++) 131 | WriteByte((byte)s[i]); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /AsycServer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace AsycServer 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | Program p = new Program(); 15 | while (true) 16 | { 17 | p.Logic(); 18 | Thread.Sleep(10); 19 | } 20 | } 21 | 22 | AsyUdpServer server; 23 | List clientList = new List(); 24 | Dictionary userList = new Dictionary(); 25 | Dictionary>> keyDic = new Dictionary>>();//关键帧 26 | private int roleId = 100000; //客户端的人物id 27 | private int frameCount = 1; //当前帧数 28 | 29 | public Program() 30 | { 31 | server = new AsyUdpServer(1255, 1337); 32 | 33 | AsyUdpServer.DebugInfo.upData = true; 34 | 35 | server.OnStart += OnStart; 36 | server.OnConnect += OnConnect; 37 | server.OnMessage += OnMessage; 38 | server.OnDisconnect += OnDisconnect; 39 | server.OnDebug += OnDebug; 40 | 41 | Thread t = new Thread(InputThread); 42 | t.Start(); 43 | } 44 | 45 | public void Logic() 46 | { 47 | server.Update(); 48 | } 49 | 50 | public void OnStart() 51 | { 52 | Console.WriteLine("Server started!"); 53 | } 54 | 55 | public void OnConnect(Client c) 56 | { 57 | Console.WriteLine("{0}[{1}, {2}] connected!", c.ID, c.tcpAdress, c.udpAdress); 58 | clientList.Add(c); 59 | 60 | MessageBuffer msg = new MessageBuffer(); 61 | msg.WriteInt(cProto.CONNECT); 62 | msg.WriteInt(roleId); 63 | c.Send(msg); 64 | roleId++; 65 | } 66 | 67 | public void OnMessage(Client c, MessageBuffer msg) 68 | { 69 | int cproto = msg.ReadInt(); 70 | switch(cproto) 71 | { 72 | case cProto.CONNECT: 73 | break; 74 | case cProto.READY: 75 | if (!userList.ContainsKey(c)) 76 | { 77 | int id = msg.ReadInt(); 78 | userList.Add(c, id); 79 | } 80 | //所有的玩家都准备好了,可以开始同步 81 | if(userList.Count >= clientList.Count) 82 | { 83 | frameCount = 1; 84 | keyDic = new Dictionary>>(); 85 | string playStr = ""; 86 | List playList = new List(); 87 | foreach(var play in userList) 88 | { 89 | CharData charData = new CharData(play.Value, play.Value+ "_" + play.Value); 90 | playList.Add(charData.ToString()); 91 | } 92 | playStr = string.Join(";", playList.ToArray()); 93 | MessageBuffer buff = new MessageBuffer(); 94 | buff.WriteInt(cProto.START); 95 | buff.WriteString(playStr); 96 | 97 | for (int i = 0; i < clientList.Count; ++i) 98 | { 99 | clientList[i].Send(buff); 100 | } 101 | } 102 | break; 103 | case cProto.SYNC_POS: 104 | for (int i = 0; i < clientList.Count; ++i) 105 | { 106 | if(c == clientList[i]) 107 | { 108 | continue; 109 | } 110 | clientList[i].Send(msg); 111 | } 112 | break; 113 | case cProto.SYNC_KEY: 114 | int clientCurFrameCount = msg.ReadInt(); 115 | string keyStr = msg.ReadString(); 116 | if(keyDic.ContainsKey(clientCurFrameCount)) 117 | { 118 | if(keyDic[clientCurFrameCount].ContainsKey(userList[c])) 119 | { 120 | keyDic[clientCurFrameCount][userList[c]].Add(keyStr); 121 | } 122 | else 123 | { 124 | keyDic[clientCurFrameCount][userList[c]] = new List(); 125 | keyDic[clientCurFrameCount][userList[c]].Add(keyStr); 126 | } 127 | } 128 | else 129 | { 130 | keyDic[clientCurFrameCount] = new Dictionary>(); 131 | keyDic[clientCurFrameCount][userList[c]] = new List(); 132 | keyDic[clientCurFrameCount][userList[c]].Add(keyStr); 133 | } 134 | if(clientCurFrameCount == frameCount) 135 | { 136 | if(keyDic[clientCurFrameCount].Count == clientList.Count) 137 | { 138 | List keyDataList = new List(); 139 | foreach(var dataList in keyDic[clientCurFrameCount].Values) 140 | { 141 | keyDataList.AddRange(dataList); 142 | } 143 | 144 | string keyData = string.Join(";", keyDataList.ToArray()); 145 | MessageBuffer buff = new MessageBuffer(); 146 | buff.WriteInt(cProto.SYNC_KEY); 147 | buff.WriteInt(frameCount); 148 | buff.WriteString(keyData); 149 | for (int i = 0; i < clientList.Count; ++i) 150 | { 151 | clientList[i].Send(buff); 152 | } 153 | frameCount += 1; 154 | } 155 | } 156 | break; 157 | case cProto.START: 158 | break; 159 | } 160 | } 161 | 162 | public void OnDisconnect(Client c) 163 | { 164 | Console.WriteLine("{0}[{1}, {2}] disconnected!", c.ID, c.tcpAdress, c.udpAdress); 165 | clientList.Remove(c); 166 | if(userList.ContainsKey(c)) 167 | { 168 | userList.Remove(c); 169 | } 170 | } 171 | 172 | public void OnDebug(string s) 173 | { 174 | Console.ForegroundColor = ConsoleColor.Green; 175 | Console.WriteLine(s); 176 | Console.ForegroundColor = ConsoleColor.Gray; 177 | } 178 | 179 | public void InputThread() 180 | { 181 | while (true) 182 | { 183 | string input = Console.ReadLine(); 184 | 185 | if (server.Active) 186 | { 187 | string[] inputArgs = input.Split(' '); 188 | if (inputArgs[0] == "quit") server.Close(); 189 | if (inputArgs[0] == "kick") server.GetClient(int.Parse(inputArgs[1])).Disconnect(); 190 | } 191 | else 192 | { 193 | if (input == "start") server.StartUp("127.0.0.1"); 194 | } 195 | } 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /AsycServer/AsyUdpServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Sockets; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace AsycServer 11 | { 12 | public class AsyUdpServer 13 | { 14 | public static class DebugInfo 15 | { 16 | public static bool upData = false; 17 | public static bool downData = false; 18 | public static bool acceptData = false; 19 | } 20 | 21 | class MessageInfo 22 | { 23 | MessageBuffer message; 24 | IPEndPoint adress; 25 | AsyUdpServer server; 26 | 27 | public MessageBuffer Message 28 | { 29 | get 30 | { 31 | return message; 32 | } 33 | set 34 | { 35 | message = value; 36 | } 37 | } 38 | public IPEndPoint Adress 39 | { 40 | get 41 | { 42 | return adress; 43 | } 44 | set 45 | { 46 | adress = value; 47 | } 48 | } 49 | 50 | public MessageInfo(MessageBuffer message, IPEndPoint endPoint, AsyUdpServer s) 51 | { 52 | server = s; 53 | Message = message; 54 | Adress = endPoint; 55 | } 56 | 57 | public void Send() 58 | { 59 | server.udpSocket.Send(message.Array, message.Size, adress); 60 | } 61 | } 62 | 63 | public static byte pingByte = byte.MaxValue; 64 | 65 | static int upByteBuffer, downByteBuffer; 66 | static int upByteTotal, downByteTotal; 67 | public static int UpBytes 68 | { 69 | get 70 | { 71 | int n = upByteBuffer; 72 | upByteBuffer = 0; 73 | 74 | return n; 75 | } 76 | } 77 | 78 | public static int DownBytes 79 | { 80 | get 81 | { 82 | int n = downByteBuffer; 83 | downByteBuffer = 0; 84 | 85 | return n; 86 | } 87 | } 88 | 89 | public static int UpBytesTotal 90 | { 91 | get 92 | { 93 | return upByteTotal; 94 | } 95 | } 96 | 97 | public static int DownBytesTotal 98 | { 99 | get 100 | { 101 | return downByteTotal; 102 | } 103 | } 104 | 105 | public delegate void StartHandle(); 106 | public delegate void ConnectHandle(Client c); 107 | public delegate void MessageHandle(Client c, MessageBuffer m); 108 | public delegate void MessageExtHandle(IPEndPoint ip, MessageBuffer m); 109 | public delegate void DisconnectHandle(Client c); 110 | public delegate void ExceptionHandle(Exception e); 111 | public delegate void PingHandle(Client c, int millis); 112 | public delegate void DebugHandle(string msg); 113 | 114 | int nmbrOfClients = 0; 115 | 116 | List disconnectedList = new List(), connectedList = new List(); 117 | List clientList = new List(); 118 | public Client GetClient(int id) 119 | { 120 | foreach (Client c in clientList) 121 | { 122 | if (c.ID == id) 123 | { 124 | return c; 125 | } 126 | } 127 | return null; 128 | } 129 | 130 | public Client GetClient(IPEndPoint ip) 131 | { 132 | foreach (Client c in clientList) 133 | { 134 | if (c.udpAdress != null && c.udpAdress.Equals(ip)) 135 | { 136 | return c; 137 | } 138 | } 139 | return null; 140 | } 141 | 142 | public event StartHandle OnStart; 143 | public event ConnectHandle OnConnect; 144 | public event DisconnectHandle OnDisconnect; 145 | public event MessageHandle OnMessage; 146 | public event MessageExtHandle OnMessageExternal; 147 | public event ExceptionHandle OnException; 148 | public event PingHandle OnPing; 149 | public event DebugHandle OnDebug; 150 | 151 | List debugMessageList = new List(); 152 | public void Debug(string s) { debugMessageList.Add(s); } 153 | List inMessages = new List(), outMessages = new List(), 154 | inMessagesExternal = new List(); 155 | 156 | UdpClient udpSocket; 157 | TcpListener tcpSocket; 158 | int tcpPort, udpPort; 159 | 160 | Thread acceptThread, receiveThread, sendThread; 161 | 162 | public bool Active 163 | { 164 | get 165 | { 166 | return udpSocket != null && tcpSocket != null; 167 | } 168 | } 169 | 170 | public string LocalIP 171 | { 172 | get 173 | { 174 | IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); 175 | string localIP = ""; 176 | 177 | foreach (IPAddress ip in host.AddressList) 178 | { 179 | if (ip.AddressFamily == AddressFamily.InterNetwork) 180 | { 181 | localIP = ip.ToString(); 182 | break; 183 | } 184 | } 185 | 186 | return localIP; 187 | } 188 | } 189 | 190 | public AsyUdpServer(int tcp, int udp) 191 | { 192 | tcpPort = tcp; 193 | udpPort = udp; 194 | } 195 | 196 | public void StartUp() { StartUp(LocalIP); } 197 | public void StartUp(string ip) 198 | { 199 | try 200 | { 201 | udpSocket = new UdpClient(udpPort); 202 | tcpSocket = new TcpListener(IPAddress.Any, tcpPort); 203 | 204 | acceptThread = new Thread(AcceptThread); 205 | receiveThread = new Thread(ReceiveThread); 206 | sendThread = new Thread(SendThread); 207 | 208 | acceptThread.Start(); 209 | receiveThread.Start(); 210 | sendThread.Start(); 211 | 212 | OnStart(); 213 | } 214 | catch (Exception e) 215 | { 216 | CatchException(e); 217 | } 218 | } 219 | 220 | 221 | public void Update() 222 | { 223 | while (inMessages.Count > 0) 224 | { 225 | OnMessage(GetClient(inMessages[0].Adress), inMessages[0].Message); 226 | inMessages.RemoveAt(0); 227 | } 228 | 229 | while (inMessagesExternal.Count > 0) 230 | { 231 | OnMessageExternal(inMessagesExternal[0].Adress, inMessagesExternal[0].Message); 232 | inMessagesExternal.RemoveAt(0); 233 | } 234 | 235 | while (connectedList.Count > 0) 236 | { 237 | OnConnect(connectedList[0]); 238 | connectedList.RemoveAt(0); 239 | } 240 | 241 | while (disconnectedList.Count > 0) 242 | { 243 | OnDisconnect(disconnectedList[0]); 244 | disconnectedList.RemoveAt(0); 245 | } 246 | 247 | while (debugMessageList.Count > 0) 248 | { 249 | OnDebug(debugMessageList[0]); 250 | debugMessageList.RemoveAt(0); 251 | } 252 | } 253 | 254 | void AcceptThread() 255 | { 256 | tcpSocket.Start(); 257 | 258 | while (Active) 259 | { 260 | try 261 | { 262 | Socket s = tcpSocket.AcceptSocket(); 263 | ClientConnected(s); 264 | } 265 | catch (Exception e) 266 | { 267 | CatchException(e); 268 | break; 269 | } 270 | } 271 | } 272 | 273 | void ReceiveThread() 274 | { 275 | while (Active) 276 | { 277 | try 278 | { 279 | IPEndPoint ip = new IPEndPoint(IPAddress.Any, 0); 280 | byte[] data = udpSocket.Receive(ref ip); 281 | 282 | if (data.Length > 0) 283 | ReceiveData(data, ip); 284 | } 285 | catch (SocketException e) 286 | { 287 | //CatchException(e); 288 | continue; 289 | } 290 | catch (Exception e) 291 | { 292 | CatchException(e); 293 | continue; 294 | } 295 | } 296 | } 297 | 298 | void ReceiveData(byte[] data, IPEndPoint ip) 299 | { 300 | if (DebugInfo.downData && data.Length > 1) 301 | { 302 | string dataString = ""; 303 | foreach (byte b in data) dataString += b + " "; 304 | Debug("Received " + data.Length + "[" + dataString + "]"); 305 | } 306 | 307 | Client c = GetClient(ip); 308 | 309 | //Pinged 310 | if (data.Length == 1 && data[0] == pingByte) 311 | { 312 | if (c != null && c.Pinging) 313 | { 314 | c.Ping(); 315 | } 316 | else 317 | { 318 | udpSocket.Send(data, 1, ip); 319 | } 320 | 321 | return; 322 | } 323 | 324 | else if (c != null) 325 | { 326 | inMessages.Add(new MessageInfo(new MessageBuffer(data), ip, this)); 327 | } 328 | else if (data.Length == 4) 329 | { 330 | int id = BitConverter.ToInt32(data, 0); 331 | c = GetClient(id); 332 | 333 | if (c != null) 334 | { 335 | if (DebugInfo.acceptData) Debug("Received udp ip for ID " + id); 336 | 337 | c.udpAdress = ip; 338 | connectedList.Add(c); 339 | } 340 | } 341 | else 342 | { 343 | inMessagesExternal.Add(new MessageInfo(new MessageBuffer(data), ip, this)); 344 | } 345 | 346 | downByteBuffer += data.Length; 347 | downByteTotal += data.Length; 348 | } 349 | 350 | void SendThread() 351 | { 352 | while (Active) 353 | { 354 | while (outMessages.Count > 0) 355 | { 356 | for (int i = 0; i < outMessages.Count; i++) 357 | { 358 | while (outMessages[i] == null) ; 359 | 360 | if (DebugInfo.downData && outMessages[0].Message.Size > 1) 361 | { 362 | string dataString = ""; 363 | foreach (byte b in outMessages[0].Message.Array) dataString += b + " "; 364 | Debug("Sending " + outMessages[0].Message.Size + "[" + dataString + "]"); 365 | } 366 | 367 | outMessages[i].Send(); 368 | upByteBuffer += outMessages[i].Message.Size; 369 | upByteTotal += outMessages[i].Message.Size; 370 | } 371 | 372 | outMessages.Clear(); 373 | } 374 | 375 | Thread.Sleep(5); 376 | } 377 | } 378 | 379 | void ClientConnected(Socket s) 380 | { 381 | Client c = new Client(nmbrOfClients, s, this); 382 | clientList.Add(c); 383 | c.SendAcceptPoll(); 384 | 385 | nmbrOfClients++; 386 | } 387 | 388 | public void ClientDisconnected(Client c) 389 | { 390 | clientList.Remove(c); 391 | disconnectedList.Add(c); 392 | } 393 | 394 | public void Send(MessageBuffer msg, int id) { Send(msg, GetClient(id)); } 395 | public void Send(MessageBuffer msg, Client c) 396 | { 397 | if (c != null && c.udpAdress != null) 398 | outMessages.Add(new MessageInfo(msg, c.udpAdress, this)); 399 | } 400 | 401 | public void SendExternal(MessageBuffer msg, IPEndPoint ip) 402 | { 403 | outMessages.Add(new MessageInfo(msg, ip, this)); 404 | } 405 | 406 | public void Close() 407 | { 408 | if (tcpSocket == null || udpSocket == null) return; 409 | 410 | tcpSocket.Stop(); 411 | udpSocket.Close(); 412 | 413 | tcpSocket = null; 414 | udpSocket = null; 415 | 416 | acceptThread.Abort(); 417 | sendThread.Abort(); 418 | receiveThread.Abort(); 419 | 420 | acceptThread = null; 421 | sendThread = null; 422 | receiveThread = null; 423 | 424 | List list = new List(); 425 | list.AddRange(clientList); 426 | 427 | foreach (Client c in list) c.Disconnect(); 428 | } 429 | 430 | public void CatchException(Exception e) 431 | { 432 | if (OnException != null) OnException(e); 433 | } 434 | 435 | public void PingResult(Client c, int millis) 436 | { 437 | if (OnPing != null) OnPing(c, millis); 438 | } 439 | } 440 | } 441 | --------------------------------------------------------------------------------