├── 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 |
--------------------------------------------------------------------------------