├── README.md ├── ScorpioNet.sln └── ScorpioNet ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── ScorpioNet.csproj ├── bin └── Debug │ └── ScorpioNet.exe └── src ├── ClientSocket.cs ├── ScorpioConnection.cs ├── ScorpioLogger.cs ├── ScorpioSocket.cs ├── ScorpioThreadPool.cs └── ServerSocket.cs /README.md: -------------------------------------------------------------------------------- 1 | # ScorpioNet 2 | * author : while 3 | * QQ讨论群 : 245199668 [加群](http://shang.qq.com/wpa/qunwpa?idkey=8ef904955c52f7b3764403ab81602b9c08b856f040d284f7e2c1d05ed3428de8) 4 | 5 | ## 数据结构: ## 6 | 7 | int(数据总长度) 8 | byte(数据类型) 9 | short(数据ID) 10 | byte[](数据内容) 11 | 12 | (2016-12-19) 13 | --- 14 | * **ServerSocket** 增加 **Shutdown** 函数,感谢 **[Shonn]** 同学的反馈 15 | 16 | (2016-12-19) 17 | --- 18 | * 支持ipv6 -------------------------------------------------------------------------------- /ScorpioNet.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScorpioNet", "ScorpioNet\ScorpioNet.csproj", "{D0F113F7-D095-4D65-B06C-F55149F63008}" 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 | {D0F113F7-D095-4D65-B06C-F55149F63008}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {D0F113F7-D095-4D65-B06C-F55149F63008}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {D0F113F7-D095-4D65-B06C-F55149F63008}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {D0F113F7-D095-4D65-B06C-F55149F63008}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ScorpioNet/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ScorpioNet/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Scorpio.Net; 8 | using System.Net.Sockets; 9 | using System.Threading; 10 | namespace ScorpioNet { 11 | public class Log : ILog { 12 | public void debug(string format) { 13 | Console.WriteLine("debug : " + format); 14 | } 15 | public void info(string format) { 16 | Console.WriteLine("info : " + format); 17 | } 18 | public void warn(string format) { 19 | Console.WriteLine("warn : " + format); 20 | } 21 | public void error(string format) { 22 | Console.WriteLine("error : " + format); 23 | } 24 | } 25 | public class ServerFactory : ScorpioConnectionFactory { 26 | public ScorpioConnection create() { 27 | return new ServerConnection(); 28 | } 29 | } 30 | public class ServerConnection : ScorpioConnection { 31 | private Dictionary m_Files = new Dictionary(); 32 | private object m_Sync = new object(); 33 | public override void OnInitialize() { 34 | Console.WriteLine("有新连接进入 " + m_Socket.GetSocket().RemoteEndPoint.ToString()); 35 | } 36 | public override void OnRecv(byte type, short msgId, int length, byte[] data) { 37 | lock (m_Sync) { 38 | if (type == 0) { 39 | string name = Path.Combine(Environment.CurrentDirectory, Encoding.UTF8.GetString(data)); 40 | if (File.Exists(name)) File.Delete(name); 41 | m_Files[msgId] = name; 42 | Console.WriteLine("开始收取 [" + name + "] 文件"); 43 | } else if (type == 1) { 44 | if (m_Files.ContainsKey(msgId)) { 45 | string name = m_Files[msgId]; 46 | using (FileStream stream = new FileStream(name, FileMode.Append)) { 47 | stream.Write(data, 0, data.Length); 48 | } 49 | } 50 | } else if (type == 2) { 51 | if (m_Files.ContainsKey(msgId)) { 52 | string name = m_Files[msgId]; 53 | m_Files.Remove(msgId); 54 | Console.WriteLine("收取文件 [" + name + "] 完成"); 55 | } 56 | } else if (type == 3) { 57 | string str = Encoding.UTF8.GetString(data); 58 | Console.WriteLine("服务器执行命令 " + str); 59 | } else { 60 | Console.WriteLine("服务器收到消息 类型 " + type + " msgId " + msgId + " 数据 : " + Encoding.UTF8.GetString(data)); 61 | m_Socket.Send(type, msgId, data); 62 | } 63 | } 64 | } 65 | public override void OnDisconnect() { 66 | Console.WriteLine("有连接断开连接"); 67 | } 68 | } 69 | public class ClientFactory : ScorpioConnectionFactory { 70 | public ScorpioConnection create() { 71 | return ClientConnection.GetInstance(); 72 | } 73 | } 74 | public class ClientConnection : ScorpioConnection { 75 | private static ClientConnection instance; 76 | public static ClientConnection GetInstance() { 77 | if (instance == null) 78 | instance = new ClientConnection(); 79 | return instance; 80 | } 81 | private short FILE_ID = 0; 82 | public override void OnInitialize() { 83 | Console.WriteLine("连接成功"); 84 | } 85 | public void SendFile(string file) { 86 | if (!File.Exists(file)) { 87 | Console.WriteLine("文件 [" + file + "] 不存在"); 88 | return; 89 | } 90 | short fileID = FILE_ID++; 91 | using (FileStream stream = File.OpenRead(file)) { 92 | Send(0, fileID, Encoding.UTF8.GetBytes(Path.GetFileName(stream.Name))); 93 | byte[] data = new byte[8192]; 94 | int count = 0; 95 | while ((count = stream.Read(data, 0, 8192)) > 0) { 96 | Send(1, fileID, data, 0, count); 97 | } 98 | Send(2, fileID, null); 99 | } 100 | } 101 | public override void OnRecv(byte type, short msgId, int length, byte[] data) { 102 | Console.WriteLine("客户端收到消息 类型 " + type + " msgId " + msgId + " 数据 : " + Encoding.UTF8.GetString(data)); 103 | } 104 | public override void OnDisconnect() { 105 | Console.WriteLine("断开连接"); 106 | } 107 | } 108 | class Program { 109 | static void Main(string[] args) { 110 | logger.SetLog(new Log()); 111 | ServerSocket server = new ServerSocket(new ServerFactory()); 112 | server.Listen(9999); 113 | ClientSocket client = new ClientSocket(new ClientFactory()); 114 | client.Connect("localhost", 9999); 115 | while (true) { 116 | string str = Console.ReadLine(); 117 | if (str.StartsWith("file ")) { 118 | ClientConnection.GetInstance().SendFile(str.Replace("file ", "")); 119 | } else if (str.StartsWith("cmd ")) { 120 | ClientConnection.GetInstance().Send(3, 0, Encoding.UTF8.GetBytes(str.Replace("cmd ", ""))); 121 | } else if (str == "exit") { 122 | ClientConnection.GetInstance().Disconnect(); 123 | break; 124 | } else if (str == "quit") { 125 | server.Shutdown(); 126 | } else { 127 | ClientConnection.GetInstance().Send(100, 9999, Encoding.UTF8.GetBytes(str)); 128 | } 129 | } 130 | Console.ReadKey(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /ScorpioNet/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("ScorpioNet")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ScorpioNet")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 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("d0f113f7-d095-4d65-b06c-f55149f63008")] 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 | -------------------------------------------------------------------------------- /ScorpioNet/ScorpioNet.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D0F113F7-D095-4D65-B06C-F55149F63008} 8 | Exe 9 | Properties 10 | ScorpioNet 11 | ScorpioNet 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 66 | -------------------------------------------------------------------------------- /ScorpioNet/bin/Debug/ScorpioNet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qingfeng346/ScorpioNet/6e9cc9b980719303d137727cb2d704bc81476823/ScorpioNet/bin/Debug/ScorpioNet.exe -------------------------------------------------------------------------------- /ScorpioNet/src/ClientSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Sockets; 4 | namespace Scorpio.Net { 5 | public enum ClientState { 6 | None, //无状态 7 | Connecting, //正在连接 8 | Connected, //已连接状态 9 | } 10 | public class ClientSocket : ScorpioHostBase { 11 | private ClientState m_State; //当前状态 12 | private ScorpioSocket m_Dispatcher; //网络信息处理 13 | private ScorpioConnection m_Connection; //网络对象 14 | private Socket m_Socket = null; //Socket句柄 15 | private SocketAsyncEventArgs m_ConnectEvent; //异步连接消息 16 | private bool m_LengthIncludesLengthFieldLength; //数据总长度是否包含 17 | public ClientSocket(ScorpioConnectionFactory factory) : this(factory, true) { } 18 | public ClientSocket(ScorpioConnectionFactory factory, bool lengthIncludesLengthFieldLength) { 19 | m_State = ClientState.None; 20 | m_LengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength; 21 | m_Connection = factory.create(); 22 | m_ConnectEvent = new SocketAsyncEventArgs(); 23 | m_ConnectEvent.Completed += ConnectionAsyncCompleted; 24 | } 25 | public ScorpioConnection GetConnection() { 26 | return m_Connection; 27 | } 28 | public void Connect(string host, int port) { 29 | if (m_State != ClientState.None) return; 30 | m_State = ClientState.Connecting; 31 | try { 32 | #if SCORPIO_DNSENDPOINT 33 | m_ConnectEvent.RemoteEndPoint = new DnsEndPoint(m_Host, m_Port); 34 | #else 35 | IPAddress address; 36 | if (host == "localhost") { 37 | m_ConnectEvent.RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port); 38 | address = IPAddress.Parse("127.0.0.1"); 39 | } else if (IPAddress.TryParse(host, out address)) { 40 | m_ConnectEvent.RemoteEndPoint = new IPEndPoint(address, port); 41 | } else { 42 | var addressList = Dns.GetHostEntry(host).AddressList; 43 | address = addressList[0]; 44 | m_ConnectEvent.RemoteEndPoint = new IPEndPoint(address, port); 45 | } 46 | #endif 47 | m_Socket = new Socket(m_ConnectEvent.RemoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 48 | m_Socket.NoDelay = false; 49 | if (!m_Socket.ConnectAsync(m_ConnectEvent)) { 50 | ConnectError("连接服务器出错 " + host + ":" + port); 51 | } 52 | } catch (System.Exception ex) { 53 | ConnectError("连接服务器出错 " + host + ":" + port + " " + ex.ToString()); 54 | }; 55 | } 56 | void ConnectionAsyncCompleted(object sender, SocketAsyncEventArgs e) { 57 | if (e.SocketError != SocketError.Success) { 58 | ConnectError("连接服务器出错 " + e.RemoteEndPoint.ToString() + " " + e.SocketError); 59 | return; 60 | } 61 | m_State = ClientState.Connected; 62 | m_Dispatcher = new ScorpioSocket(m_Socket, m_LengthIncludesLengthFieldLength); 63 | m_Connection.SetSocket(this, m_Dispatcher); 64 | } 65 | void ConnectError(string error) { 66 | m_State = ClientState.None; 67 | logger.error(error); 68 | m_Connection.OnConnectError(error); 69 | } 70 | public void OnDisconnect(ScorpioConnection connection) { 71 | 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /ScorpioNet/src/ScorpioConnection.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | namespace Scorpio.Net { 3 | public interface ScorpioConnectionFactory { 4 | ScorpioConnection create(); 5 | } 6 | public interface ScorpioHostBase { 7 | void OnDisconnect(ScorpioConnection connection); 8 | } 9 | public abstract class ScorpioConnection { 10 | private bool m_Closed = true; 11 | protected ScorpioSocket m_Socket; 12 | protected ScorpioHostBase m_Host; 13 | internal void SetSocket(ScorpioHostBase host, ScorpioSocket socket) { 14 | m_Host = host; 15 | m_Socket = socket; 16 | m_Socket.SetConnection(this); 17 | m_Closed = false; 18 | OnInitialize(); 19 | } 20 | public void Send(byte type, short msgId, byte[] data) { m_Socket.Send(type, msgId, data); } 21 | public void Send(byte type, short msgId, byte[] data, int offset, int count) { m_Socket.Send(type, msgId, data, offset, count); } 22 | public void Disconnect() { 23 | if (m_Closed) { return; } 24 | m_Closed = true; 25 | try { 26 | using (var socket = m_Socket.GetSocket()) { 27 | socket.Shutdown(SocketShutdown.Both); 28 | socket.Close(); 29 | } 30 | } catch (System.Exception e) { 31 | logger.error("Connection Disconnect is error : " + e.ToString()); 32 | } finally { 33 | try { 34 | if (m_Host != null) m_Host.OnDisconnect(this); 35 | OnDisconnect(); 36 | } catch (System.Exception e) { 37 | logger.error("Connection OnDisconnect is error : " + e.ToString()); 38 | } 39 | } 40 | } 41 | public virtual void OnInitialize() { } 42 | public virtual void OnConnectError(string error) { } 43 | public virtual void OnDisconnect() { } 44 | public virtual void OnRecv(byte type, short msgId, int length, byte[] data) { } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ScorpioNet/src/ScorpioLogger.cs: -------------------------------------------------------------------------------- 1 | namespace Scorpio.Net { 2 | public interface ILog { 3 | /// debug 信息 4 | void debug(string format); 5 | /// info 信息 6 | void info(string format); 7 | /// 警告 信息 8 | void warn(string format); 9 | /// 错误 信息 10 | void error(string format); 11 | } 12 | public static class logger { 13 | private static ILog log = null; 14 | /// 设置日志对象 15 | public static void SetLog(ILog ilog) { 16 | log = ilog; 17 | } 18 | /// debug输出 19 | public static void debug(string format) { 20 | if (log == null) return; 21 | log.debug(format); 22 | } 23 | /// info输出 24 | public static void info(string format) { 25 | if (log == null) return; 26 | log.info(format); 27 | } 28 | /// warn输出 29 | public static void warn(string format) { 30 | if (log == null) return; 31 | log.warn(format); 32 | } 33 | /// error输出 34 | public static void error(string format) { 35 | if (log == null) return; 36 | log.error(format); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ScorpioNet/src/ScorpioSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Sockets; 4 | namespace Scorpio.Net { 5 | public class ScorpioSocket { 6 | private const int MAX_BUFFER_LENGTH = 8192; // 缓冲区大小 7 | private byte[] m_RecvTokenBuffer = new byte[MAX_BUFFER_LENGTH]; // 已经接收的数据总缓冲 8 | private int m_RecvTokenSize = 0; // 接收总数据的长度 9 | private bool m_Sending; // 是否正在发送消息 10 | private Socket m_Socket = null; // Socket句柄 11 | private Queue m_SendQueue = new Queue(); // 发送消息队列 12 | private object m_SendSync = new object(); // 发送消息线程锁 13 | private SocketAsyncEventArgs m_RecvEvent = null; // 异步接收消息 14 | private SocketAsyncEventArgs m_SendEvent = null; // 异步发送消息 15 | private ScorpioConnection m_Connection = null; // 连接 16 | private bool m_LengthIncludesLengthFieldLength; // 数据总长度是否包含 17 | public ScorpioSocket(Socket socket, bool lengthIncludesLengthFieldLength) { 18 | m_Socket = socket; 19 | m_LengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength; 20 | m_SendEvent = new SocketAsyncEventArgs(); 21 | m_SendEvent.Completed += SendAsyncCompleted; 22 | m_RecvEvent = new SocketAsyncEventArgs(); 23 | m_RecvEvent.SetBuffer(new byte[MAX_BUFFER_LENGTH], 0, MAX_BUFFER_LENGTH); 24 | m_RecvEvent.Completed += RecvAsyncCompleted; 25 | } 26 | //设置socket句柄 27 | public void SetConnection(ScorpioConnection connection) { 28 | m_Connection = connection; 29 | m_Sending = false; 30 | m_RecvTokenSize = 0; 31 | Array.Clear(m_RecvTokenBuffer, 0, m_RecvTokenBuffer.Length); 32 | Array.Clear(m_RecvEvent.Buffer, 0, m_RecvEvent.Buffer.Length); 33 | m_SendQueue.Clear(); 34 | BeginReceive(); 35 | } 36 | public Socket GetSocket() { 37 | return m_Socket; 38 | } 39 | public void Send(byte type, short msgId, byte[] data) { 40 | Send(type, msgId, data, 0, data != null ? data.Length : 0); 41 | } 42 | //发送协议 43 | public void Send(byte type, short msgId, byte[] data, int offset, int length) { 44 | if (!m_Socket.Connected) { return; } 45 | int count = length + 7; //协议头长度 数据长度int(4个字节) + 数据类型byte(1个字节) + 协议IDshort(2个字节) 46 | byte[] buffer = new byte[count]; 47 | Array.Copy(BitConverter.GetBytes(m_LengthIncludesLengthFieldLength ? count : count - 4), buffer, 4); //写入数据长度 48 | buffer[4] = type; //写入数据类型 49 | Array.Copy(BitConverter.GetBytes(msgId), 0, buffer, 5, 2); //写入数据ID 50 | if (data != null) Array.Copy(data, offset, buffer, 7, length); //写入数据内容 51 | lock (m_SendQueue) { m_SendQueue.Enqueue(buffer); } 52 | ScorpioThreadPool.CreateThread(() => { BeginSend(); }); 53 | } 54 | void BeginSend() { 55 | lock (m_SendSync) { 56 | if (m_Sending || m_SendQueue.Count <= 0) return; 57 | m_Sending = true; 58 | byte[] data = null; 59 | lock (m_SendQueue) { data = m_SendQueue.Dequeue(); } 60 | SendInternal(data, 0, data.Length); 61 | } 62 | } 63 | void SendInternal(byte[] data, int offset, int length) { 64 | var completedAsync = false; 65 | try { 66 | if (data == null) 67 | m_SendEvent.SetBuffer(offset, length); 68 | else 69 | m_SendEvent.SetBuffer(data, offset, length); 70 | completedAsync = m_Socket.SendAsync(m_SendEvent); 71 | } catch (System.Exception ex) { 72 | LogError("发送数据出错 : " + ex.ToString()); 73 | Disconnect(SocketError.SocketError); 74 | } 75 | if (!completedAsync) { 76 | m_SendEvent.SocketError = SocketError.Fault; 77 | SendAsyncCompleted(this, m_SendEvent); 78 | } 79 | } 80 | void SendAsyncCompleted(object sender, SocketAsyncEventArgs e) { 81 | if (e.SocketError != SocketError.Success) { 82 | LogError("发送数据出错 : " + e.SocketError); 83 | Disconnect(e.SocketError); 84 | return; 85 | } 86 | lock (m_SendSync) { 87 | if (e.Offset + e.BytesTransferred < e.Count) { 88 | SendInternal(null, e.Offset + e.BytesTransferred, e.Count - e.BytesTransferred - e.Offset); 89 | } else { 90 | m_Sending = false; 91 | BeginSend(); 92 | } 93 | } 94 | } 95 | //开始接收消息 96 | void BeginReceive() { 97 | try { 98 | if (!m_Socket.ReceiveAsync(m_RecvEvent)) { 99 | LogError("接收数据失败"); 100 | Disconnect(SocketError.SocketError); 101 | } 102 | } catch (System.Exception e) { 103 | LogError("接收数据出错 : " + e.ToString()); 104 | Disconnect(SocketError.SocketError); 105 | } 106 | } 107 | void RecvAsyncCompleted(object sender, SocketAsyncEventArgs e) { 108 | if (e.SocketError != SocketError.Success) { 109 | LogError("接收数据出错 : " + e.SocketError); 110 | Disconnect(e.SocketError); 111 | } else { 112 | while (m_RecvTokenSize + e.BytesTransferred >= m_RecvTokenBuffer.Length) { 113 | byte[] bytes = new byte[m_RecvTokenBuffer.Length * 2]; 114 | Array.Copy(m_RecvTokenBuffer, 0, bytes, 0, m_RecvTokenSize); 115 | m_RecvTokenBuffer = bytes; 116 | } 117 | Array.Copy(e.Buffer, 0, m_RecvTokenBuffer, m_RecvTokenSize, e.BytesTransferred); 118 | m_RecvTokenSize += e.BytesTransferred; 119 | try { 120 | ParsePackage(); 121 | } catch (System.Exception ex) { 122 | LogError("解析数据出错 : " + ex.ToString()); 123 | Disconnect(SocketError.SocketError); 124 | return; 125 | } 126 | BeginReceive(); 127 | } 128 | } 129 | void ParsePackage() { 130 | for ( ; ; ) { 131 | if (m_RecvTokenSize < 4) break; 132 | int size = BitConverter.ToInt32(m_RecvTokenBuffer, 0) + (m_LengthIncludesLengthFieldLength ? 0 : 4); 133 | if (m_RecvTokenSize < size) break; 134 | byte type = m_RecvTokenBuffer[4]; 135 | short msgId = BitConverter.ToInt16(m_RecvTokenBuffer, 5); 136 | int length = size - 7; 137 | byte[] buffer = new byte[length]; 138 | Array.Copy(m_RecvTokenBuffer, 7, buffer, 0, length); 139 | OnRecv(type, msgId, length, buffer); 140 | m_RecvTokenSize -= size; 141 | if (m_RecvTokenSize > 0) Array.Copy(m_RecvTokenBuffer, size, m_RecvTokenBuffer, 0, m_RecvTokenSize); 142 | } 143 | } 144 | void Disconnect(SocketError error) { 145 | m_Connection.Disconnect(); 146 | } 147 | void OnRecv(byte type, short msgId, int length, byte[] data) { 148 | m_Connection.OnRecv(type, msgId, length, data); 149 | } 150 | void LogError(string error) { 151 | logger.error(error); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /ScorpioNet/src/ScorpioThreadPool.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace Scorpio.Net { 4 | public class ScorpioThreadPool { 5 | public delegate void ScorpioThreadHandler(); 6 | public static void CreateThread(ScorpioThreadHandler handler) { 7 | ThreadPool.QueueUserWorkItem(_ => { handler(); }); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ScorpioNet/src/ServerSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net; 4 | using System.Net.Sockets; 5 | namespace Scorpio.Net { 6 | public enum ServerState { 7 | None, //无状态 8 | Listened, //监听状态 9 | } 10 | public class ServerSocket : ScorpioHostBase { 11 | private ScorpioConnectionFactory m_Factory; 12 | private ServerState m_State; 13 | private Socket m_Socket; 14 | private List m_Connects = new List(); 15 | private SocketAsyncEventArgs m_AcceptEvent = null; 16 | private bool m_LengthIncludesLengthFieldLength; //数据总长度是否包含 17 | public ServerSocket(ScorpioConnectionFactory factory) : this (factory, true) { } 18 | public ServerSocket(ScorpioConnectionFactory factory, bool lengthIncludesLengthFieldLength) { 19 | m_Factory = factory; 20 | m_LengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength; 21 | m_State = ServerState.None; 22 | } 23 | public void Listen(int port) { 24 | if (m_State != ServerState.None) return; 25 | try { 26 | m_AcceptEvent = new SocketAsyncEventArgs(); 27 | m_AcceptEvent.Completed += AcceptAsyncCompleted; 28 | m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 29 | m_Socket.NoDelay = false; 30 | m_Socket.Bind(new IPEndPoint(IPAddress.Any, port)); 31 | m_Socket.Listen(10); 32 | m_State = ServerState.Listened; 33 | BeginAccept(); 34 | } catch (System.Exception ex) { 35 | m_State = ServerState.None; 36 | logger.error("服务器监听失败 [" + port + "] " + ex.ToString()); 37 | }; 38 | } 39 | void BeginAccept() { 40 | bool completed = false; 41 | try { 42 | completed = m_Socket.AcceptAsync(m_AcceptEvent); 43 | } catch (System.Exception ex) { 44 | logger.error("Accept出现错误 : " + ex.ToString()); 45 | } 46 | if (!completed) ScorpioThreadPool.CreateThread(() => { BeginAccept(); }); 47 | } 48 | void AcceptAsyncCompleted(object sender, SocketAsyncEventArgs e) { 49 | var error = e.SocketError; 50 | if (error != SocketError.Success) { 51 | if (error == SocketError.OperationAborted || error == SocketError.Interrupted || error == SocketError.NotSocket) 52 | return; 53 | m_Socket.AcceptAsync(m_AcceptEvent); 54 | return; 55 | } 56 | var connection = m_Factory.create(); 57 | connection.SetSocket(this, new ScorpioSocket(m_AcceptEvent.AcceptSocket, m_LengthIncludesLengthFieldLength)); 58 | m_Connects.Add(connection); 59 | m_AcceptEvent.AcceptSocket = null; 60 | BeginAccept(); 61 | } 62 | public void OnDisconnect(ScorpioConnection connection) { 63 | m_Connects.Remove(connection); 64 | } 65 | public void Shutdown() { 66 | if (m_State == ServerState.None) { return; } 67 | m_State = ServerState.None; 68 | try { 69 | m_AcceptEvent.Completed -= AcceptAsyncCompleted; 70 | m_AcceptEvent.Dispose(); 71 | m_AcceptEvent = null; 72 | m_Socket.Close(); 73 | while (m_Connects.Count > 0) { 74 | m_Connects[0].Disconnect(); 75 | } 76 | } finally { 77 | m_Socket = null; 78 | } 79 | } 80 | } 81 | } 82 | --------------------------------------------------------------------------------