├── .gitignore
├── README.md
├── dist
├── SimpleJson.dll
└── pomelo-dotnetClient.dll
├── lib
└── SimpleJson.dll
├── pomelo-dotnetClient.sln
├── pomelo-dotnetClient
├── pomelo-dotnetClient.csproj
└── src
│ ├── client
│ ├── EventManager.cs
│ ├── PomeloClient.cs
│ └── test
│ │ └── ClientTest.cs
│ ├── protobuf
│ ├── Decoder.cs
│ ├── Encoder.cs
│ ├── MsgDecoder.cs
│ ├── MsgEncoder.cs
│ ├── Protobuf.cs
│ ├── test
│ │ ├── CodecTest.cs
│ │ └── ProtobufTest.cs
│ └── util
│ │ └── Util.cs
│ ├── protocol
│ ├── HandShakeService.cs
│ ├── HeartBeatService.cs
│ ├── Message.cs
│ ├── MessageProtocol.cs
│ ├── MessageType.cs
│ ├── Package.cs
│ ├── PackageProtocol.cs
│ ├── PackageTypes.cs
│ ├── Protocol.cs
│ └── ProtocolState.cs
│ └── transport
│ ├── TransportState.cs
│ ├── Transporter.cs
│ └── test
│ └── TransportTest.cs
└── test
├── Test.cs
├── json
├── msg.json
├── protos.json
├── rootMsg.json
└── rootProtos.json
└── test.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific files
2 | *.suo
3 | *.user
4 | *.log
5 | *.userprefs
6 | *.pdb
7 |
8 | # directories
9 | /pomelo-dotnetClient/obj
10 | /pomelo-dotnetClient/bin
11 | /test/obj
12 | /test/bin
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | pomelo-unityclient-socket
2 | =============================
3 | This is the pomelo dotnet client, support pomelo 0.3 and the new communicate protocol.It is based on native socket.
4 | The project is based on some libraries as follows:
5 |
6 | * [simple-json](https://github.com/facebook-csharp-sdk/simple-json) An open source json library
7 |
8 | ## Demo
9 |
10 | * [Unity3D demo](https://github.com/NetEase/pomelo-unitychat-socket) A pomelo-chat client use unity 3D.
11 | * [dotnet demo](https://github.com/NetEase/pomelo-dotnetchat-console) A pomelo-chat client use console and write by c#.
12 |
13 | ## How to use
14 | To use the dotnetClient, just include ./dist/*.dll in your project.
15 |
16 | ## API
17 |
18 | Initialize pomelo client
19 |
20 | ```c#
21 | using namespace Pomelo.DotNetClient
22 | string host="127.0.0.1";//(www.xxx.com/127.0.0.1/::1/localhost etc.)
23 | int port=3014;
24 | PomeloClient pclient = new PomeloClient();
25 |
26 | //listen on network state changed event
27 | pclient.NetWorkStateChangedEvent += (state) =>
28 | {
29 | Console.WriteLine(state);
30 | };
31 |
32 | pclient.initClient(host, port, () =>
33 | {
34 | //The user data is the handshake user params
35 | JsonObject user = new JsonObject();
36 | pclient.connect(user, data =>
37 | {
38 | //process handshake call back data
39 | });
40 | });
41 |
42 | ```
43 |
44 | Use request and response
45 | ```c#
46 | pclient.request(route, message, (data)=>{
47 | //process the data
48 | });
49 | ```
50 |
51 | Notify server without response
52 |
53 | ```c#
54 | pclient.notify(route, messge);
55 | ```
56 |
57 | Add event listener, process broadcast message
58 | ```c#
59 | pclient.on(route, (data)=>{
60 | //process the data
61 | });
62 | ```
63 | Disconnect the client.
64 | ```c#
65 | pclient.disconnect();
66 | ```
67 |
68 | protobuf surpported type:`uInt32, int32, sInt32, float, double, string.`
69 |
70 | The dotnet client support dictionary compress and protbuf encode. The use these function, just set the flag at server side.
71 | ##License
72 | (The MIT License)
73 |
74 | Copyright (c) 2012-2013 NetEase, Inc. and other contributors
75 |
76 | Permission is hereby granted, free of charge, to any person obtaining a
77 | copy of this software and associated documentation files (the 'Software'),
78 | to deal in the Software without restriction, including without limitation
79 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
80 | and/or sell copies of the Software, and to permit persons to whom the
81 | Software is furnished to do so, subject to the following conditions:
82 |
83 | The above copyright notice and this permission notice shall be included in
84 | all copies or substantial portions of the Software.
85 |
86 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
87 |
--------------------------------------------------------------------------------
/dist/SimpleJson.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NetEase/pomelo-unityclient-socket/e4a3b70593839204e91a280f27a3a092d1d18a2b/dist/SimpleJson.dll
--------------------------------------------------------------------------------
/dist/pomelo-dotnetClient.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NetEase/pomelo-unityclient-socket/e4a3b70593839204e91a280f27a3a092d1d18a2b/dist/pomelo-dotnetClient.dll
--------------------------------------------------------------------------------
/lib/SimpleJson.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NetEase/pomelo-unityclient-socket/e4a3b70593839204e91a280f27a3a092d1d18a2b/lib/SimpleJson.dll
--------------------------------------------------------------------------------
/pomelo-dotnetClient.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pomelo-dotnetClient", "pomelo-dotnetClient\pomelo-dotnetClient.csproj", "{0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{0FFBA04C-F690-41DB-A795-BD6EC44C04AA}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|Mixed Platforms = Debug|Mixed Platforms
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|Mixed Platforms = Release|Mixed Platforms
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Debug|Any CPU.ActiveCfg = Debug|x86
21 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
22 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Debug|Mixed Platforms.Build.0 = Debug|x86
23 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Debug|x86.ActiveCfg = Debug|x86
24 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Debug|x86.Build.0 = Debug|x86
25 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Release|Any CPU.ActiveCfg = Release|x86
26 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Release|Mixed Platforms.ActiveCfg = Release|x86
27 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Release|Mixed Platforms.Build.0 = Release|x86
28 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Release|x86.ActiveCfg = Release|x86
29 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}.Release|x86.Build.0 = Release|x86
30 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
33 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
34 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Debug|x86.ActiveCfg = Debug|Any CPU
35 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
38 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
39 | {0FFBA04C-F690-41DB-A795-BD6EC44C04AA}.Release|x86.ActiveCfg = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(SolutionProperties) = preSolution
42 | HideSolutionNode = FALSE
43 | EndGlobalSection
44 | GlobalSection(MonoDevelopProperties) = preSolution
45 | StartupItem = pomelo-dotnetClient\pomelo-dotnetClient.csproj
46 | EndGlobalSection
47 | EndGlobal
48 |
--------------------------------------------------------------------------------
/pomelo-dotnetClient/pomelo-dotnetClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 10.0.0
7 | 2.0
8 | {0752F53D-46EF-44E2-AAA9-F2FAB9F0C4FA}
9 | Library
10 | pomelodotnetClient
11 | pomelo-dotnetClient
12 |
13 |
14 | true
15 | full
16 | false
17 | bin\Debug
18 | DEBUG;
19 | prompt
20 | 4
21 | x86
22 | false
23 |
24 |
25 | none
26 | true
27 | ..\dist\
28 | prompt
29 | 4
30 | x86
31 | false
32 |
33 |
34 |
35 |
36 | ..\lib\SimpleJson.dll
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/pomelo-dotnetClient/src/client/EventManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using SimpleJson;
5 |
6 | namespace Pomelo.DotNetClient
7 | {
8 | public class EventManager : IDisposable
9 | {
10 | private Dictionary> callBackMap;
11 | private Dictionary>> eventMap;
12 |
13 | public EventManager()
14 | {
15 | this.callBackMap = new Dictionary>();
16 | this.eventMap = new Dictionary>>();
17 | }
18 |
19 | //Adds callback to callBackMap by id.
20 | public void AddCallBack(uint id, Action callback)
21 | {
22 | if (id > 0 && callback != null)
23 | {
24 | this.callBackMap.Add(id, callback);
25 | }
26 | }
27 |
28 | ///
29 | /// Invoke the callback when the server return messge .
30 | ///
31 | ///
32 | /// Pomelo message.
33 | ///
34 | public void InvokeCallBack(uint id, JsonObject data)
35 | {
36 | if (!callBackMap.ContainsKey(id)) return;
37 | callBackMap[id].Invoke(data);
38 | }
39 |
40 | //Adds the event to eventMap by name.
41 | public void AddOnEvent(string eventName, Action callback)
42 | {
43 | List> list = null;
44 | if (this.eventMap.TryGetValue(eventName, out list))
45 | {
46 | list.Add(callback);
47 | }
48 | else
49 | {
50 | list = new List>();
51 | list.Add(callback);
52 | this.eventMap.Add(eventName, list);
53 | }
54 | }
55 |
56 | ///
57 | /// If the event exists,invoke the event when server return messge.
58 | ///
59 | ///
60 | ///
61 | ///
62 | ///
63 | public void InvokeOnEvent(string route, JsonObject msg)
64 | {
65 | if (!this.eventMap.ContainsKey(route)) return;
66 |
67 | List> list = eventMap[route];
68 | foreach (Action action in list) action.Invoke(msg);
69 | }
70 |
71 | // Dispose() calls Dispose(true)
72 | public void Dispose()
73 | {
74 | Dispose(true);
75 | GC.SuppressFinalize(this);
76 | }
77 |
78 | // The bulk of the clean-up code is implemented in Dispose(bool)
79 | protected void Dispose(bool disposing)
80 | {
81 | this.callBackMap.Clear();
82 | this.eventMap.Clear();
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/pomelo-dotnetClient/src/client/PomeloClient.cs:
--------------------------------------------------------------------------------
1 | using SimpleJson;
2 | using System;
3 | using System.ComponentModel;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Threading;
7 |
8 | namespace Pomelo.DotNetClient
9 | {
10 | ///
11 | /// network state enum
12 | ///
13 | public enum NetWorkState
14 | {
15 | [Description("initial state")]
16 | CLOSED,
17 |
18 | [Description("connecting server")]
19 | CONNECTING,
20 |
21 | [Description("server connected")]
22 | CONNECTED,
23 |
24 | [Description("disconnected with server")]
25 | DISCONNECTED,
26 |
27 | [Description("connect timeout")]
28 | TIMEOUT,
29 |
30 | [Description("netwrok error")]
31 | ERROR
32 | }
33 |
34 | public class PomeloClient : IDisposable
35 | {
36 | ///
37 | /// netwrok changed event
38 | ///
39 | public event Action NetWorkStateChangedEvent;
40 |
41 |
42 | private NetWorkState netWorkState = NetWorkState.CLOSED; //current network state
43 |
44 | private EventManager eventManager;
45 | private Socket socket;
46 | private Protocol protocol;
47 | private bool disposed = false;
48 | private uint reqId = 1;
49 |
50 | private ManualResetEvent timeoutEvent = new ManualResetEvent(false);
51 | private int timeoutMSec = 8000; //connect timeout count in millisecond
52 |
53 | public PomeloClient()
54 | {
55 | }
56 |
57 | ///
58 | /// initialize pomelo client
59 | ///
60 | /// server name or server ip (www.xxx.com/127.0.0.1/::1/localhost etc.)
61 | /// server port
62 | /// socket successfully connected callback(in network thread)
63 | public void initClient(string host, int port, Action callback = null)
64 | {
65 | timeoutEvent.Reset();
66 | eventManager = new EventManager();
67 | NetWorkChanged(NetWorkState.CONNECTING);
68 |
69 | IPAddress ipAddress = null;
70 |
71 | try
72 | {
73 | IPAddress[] addresses = Dns.GetHostEntry(host).AddressList;
74 | foreach (var item in addresses)
75 | {
76 | if (item.AddressFamily == AddressFamily.InterNetwork)
77 | {
78 | ipAddress = item;
79 | break;
80 | }
81 | }
82 | }
83 | catch (Exception e)
84 | {
85 | NetWorkChanged(NetWorkState.ERROR);
86 | return;
87 | }
88 |
89 | if (ipAddress == null)
90 | {
91 | throw new Exception("can not parse host : " + host);
92 | }
93 |
94 | this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
95 | IPEndPoint ie = new IPEndPoint(ipAddress, port);
96 |
97 | socket.BeginConnect(ie, new AsyncCallback((result) =>
98 | {
99 | try
100 | {
101 | this.socket.EndConnect(result);
102 | this.protocol = new Protocol(this, this.socket);
103 | NetWorkChanged(NetWorkState.CONNECTED);
104 |
105 | if (callback != null)
106 | {
107 | callback();
108 | }
109 | }
110 | catch (SocketException e)
111 | {
112 | if (netWorkState != NetWorkState.TIMEOUT)
113 | {
114 | NetWorkChanged(NetWorkState.ERROR);
115 | }
116 | Dispose();
117 | }
118 | finally
119 | {
120 | timeoutEvent.Set();
121 | }
122 | }), this.socket);
123 |
124 | if (timeoutEvent.WaitOne(timeoutMSec, false))
125 | {
126 | if (netWorkState != NetWorkState.CONNECTED && netWorkState != NetWorkState.ERROR)
127 | {
128 | NetWorkChanged(NetWorkState.TIMEOUT);
129 | Dispose();
130 | }
131 | }
132 | }
133 |
134 | ///
135 | /// 网络状态变化
136 | ///
137 | ///
138 | private void NetWorkChanged(NetWorkState state)
139 | {
140 | netWorkState = state;
141 |
142 | if (NetWorkStateChangedEvent != null)
143 | {
144 | NetWorkStateChangedEvent(state);
145 | }
146 | }
147 |
148 | public void connect()
149 | {
150 | connect(null, null);
151 | }
152 |
153 | public void connect(JsonObject user)
154 | {
155 | connect(user, null);
156 | }
157 |
158 | public void connect(Action handshakeCallback)
159 | {
160 | connect(null, handshakeCallback);
161 | }
162 |
163 | public bool connect(JsonObject user, Action handshakeCallback)
164 | {
165 | try
166 | {
167 | protocol.start(user, handshakeCallback);
168 | return true;
169 | }
170 | catch (Exception e)
171 | {
172 | Console.WriteLine(e.ToString());
173 | return false;
174 | }
175 | }
176 |
177 | private JsonObject emptyMsg = new JsonObject();
178 | public void request(string route, Action action)
179 | {
180 | this.request(route, emptyMsg, action);
181 | }
182 |
183 | public void request(string route, JsonObject msg, Action action)
184 | {
185 | this.eventManager.AddCallBack(reqId, action);
186 | protocol.send(route, reqId, msg);
187 |
188 | reqId++;
189 | }
190 |
191 | public void notify(string route, JsonObject msg)
192 | {
193 | protocol.send(route, msg);
194 | }
195 |
196 | public void on(string eventName, Action action)
197 | {
198 | eventManager.AddOnEvent(eventName, action);
199 | }
200 |
201 | internal void processMessage(Message msg)
202 | {
203 | if (msg.type == MessageType.MSG_RESPONSE)
204 | {
205 | //msg.data["__route"] = msg.route;
206 | //msg.data["__type"] = "resp";
207 | eventManager.InvokeCallBack(msg.id, msg.data);
208 | }
209 | else if (msg.type == MessageType.MSG_PUSH)
210 | {
211 | //msg.data["__route"] = msg.route;
212 | //msg.data["__type"] = "push";
213 | eventManager.InvokeOnEvent(msg.route, msg.data);
214 | }
215 | }
216 |
217 | public void disconnect()
218 | {
219 | Dispose();
220 | NetWorkChanged(NetWorkState.DISCONNECTED);
221 | }
222 |
223 | public void Dispose()
224 | {
225 | Dispose(true);
226 | GC.SuppressFinalize(this);
227 | }
228 |
229 | // The bulk of the clean-up code
230 | protected virtual void Dispose(bool disposing)
231 | {
232 | if (this.disposed)
233 | return;
234 |
235 | if (disposing)
236 | {
237 | // free managed resources
238 | if (this.protocol != null)
239 | {
240 | this.protocol.close();
241 | }
242 |
243 | if (this.eventManager != null)
244 | {
245 | this.eventManager.Dispose();
246 | }
247 |
248 | try
249 | {
250 | this.socket.Shutdown(SocketShutdown.Both);
251 | this.socket.Close();
252 | this.socket = null;
253 | }
254 | catch (Exception)
255 | {
256 | //todo : 有待确定这里是否会出现异常,这里是参考之前官方github上pull request。emptyMsg
257 | }
258 |
259 | this.disposed = true;
260 | }
261 | }
262 | }
263 | }
--------------------------------------------------------------------------------
/pomelo-dotnetClient/src/client/test/ClientTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using SimpleJson;
3 |
4 | namespace Pomelo.DotNetClient.Test
5 | {
6 | public class ClientTest
7 | {
8 | public static PomeloClient pc = null;
9 |
10 | public static void loginTest(string host, int port)
11 | {
12 | pc = new PomeloClient();
13 |
14 | pc.NetWorkStateChangedEvent += (state) =>
15 | {
16 | Console.WriteLine(state);
17 | };
18 |
19 |
20 | pc.initClient(host, port, () =>
21 | {
22 | pc.connect(null, data =>
23 | {
24 |
25 | Console.WriteLine("on data back" + data.ToString());
26 | JsonObject msg = new JsonObject();
27 | msg["uid"] = 111;
28 | pc.request("gate.gateHandler.queryEntry", msg, OnQuery);
29 | });
30 | });
31 | }
32 |
33 | public static void OnQuery(JsonObject result)
34 | {
35 | if (Convert.ToInt32(result["code"]) == 200)
36 | {
37 | pc.disconnect();
38 |
39 | string host = (string)result["host"];
40 | int port = Convert.ToInt32(result["port"]);
41 | pc = new PomeloClient();
42 |
43 | pc.NetWorkStateChangedEvent += (state) =>
44 | {
45 | Console.WriteLine(state);
46 | };
47 |
48 | pc.initClient(host, port, () =>
49 | {
50 | pc.connect(null, (data) =>
51 | {
52 | JsonObject userMessage = new JsonObject();
53 | Console.WriteLine("on connect to connector!");
54 |
55 | //Login
56 | JsonObject msg = new JsonObject();
57 | msg["username"] = "test";
58 | msg["rid"] = "pomelo";
59 |
60 | pc.request("connector.entryHandler.enter", msg, OnEnter);
61 | });
62 | });
63 | }
64 | }
65 |
66 | public static void OnEnter(JsonObject result)
67 | {
68 | Console.WriteLine("on login " + result.ToString());
69 | }
70 |
71 | public static void onDisconnect(JsonObject result)
72 | {
73 | Console.WriteLine("on sockect disconnected!");
74 | }
75 |
76 | public static void Run()
77 | {
78 | string host = "192.168.0.156";
79 | int port = 3014;
80 |
81 | loginTest(host, port);
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/pomelo-dotnetClient/src/protobuf/Decoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Pomelo.Protobuf
4 | {
5 | public class Decoder
6 | {
7 | ///
8 | /// Decodes the UInt32.
9 | ///
10 | public static uint decodeUInt32(int offset, byte[] bytes, out int length)
11 | {
12 | uint n = 0;
13 | length = 0;
14 |
15 | for (int i = offset; i < bytes.Length; i++)
16 | {
17 | length++;
18 | uint m = Convert.ToUInt32(bytes[i]);
19 | n = n + Convert.ToUInt32((m & 0x7f) * Math.Pow(2, (7 * (i - offset))));
20 | if (m < 128)
21 | {
22 | break;
23 | }
24 | }
25 |
26 | return n;
27 | }
28 |
29 | public static uint decodeUInt32(byte[] bytes)
30 | {
31 | int length;
32 | return decodeUInt32(0, bytes, out length);
33 | }
34 |
35 | ///
36 | /// Decodes the SInt32.
37 | ///
38 | public static int decodeSInt32(byte[] bytes)
39 | {
40 | uint n = decodeUInt32(bytes);
41 | int flag = ((n % 2) == 1) ? -1 : 1;
42 |
43 | int result = Convert.ToInt32(((n % 2 + n) / 2) * flag);
44 | return result;
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/pomelo-dotnetClient/src/protobuf/Encoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | namespace Pomelo.Protobuf
6 | {
7 | public class Encoder
8 | {
9 |
10 | //Encode the UInt32.
11 | public static byte[] encodeUInt32(string n)
12 | {
13 | return encodeUInt32(Convert.ToUInt32(n));
14 | }
15 |
16 | ///
17 | /// Encode the UInt32.
18 | ///
19 | ///
20 | /// byte[]
21 | ///
22 | ///
23 | /// int
24 | ///
25 | public static byte[] encodeUInt32(uint n)
26 | {
27 | List byteList = new List();
28 | do
29 | {
30 | uint tmp = n % 128;
31 | uint next = n >> 7;
32 | if (next != 0)
33 | {
34 | tmp = tmp + 128;
35 | }
36 | byteList.Add(Convert.ToByte(tmp));
37 | n = next;
38 | } while (n != 0);
39 |
40 | return byteList.ToArray();
41 | }
42 |
43 | //Encode SInt32
44 | public static byte[] encodeSInt32(string n)
45 | {
46 | return encodeSInt32(Convert.ToInt32(n));
47 | }
48 |
49 | ///
50 | /// Encodes the SInt32.
51 | ///
52 | ///
53 | /// byte []
54 | ///
55 | ///
56 | /// int
57 | ///
58 | public static byte[] encodeSInt32(int n)
59 | {
60 | UInt32 num = (uint)(n < 0 ? (Math.Abs(n) * 2 - 1) : n * 2);
61 | return encodeUInt32(num);
62 | }
63 |
64 | ///
65 | /// Encodes the float.
66 | ///
67 | ///
68 | /// byte []
69 | ///
70 | ///
71 | /// float.
72 | ///
73 | public static byte[] encodeFloat(float n)
74 | {
75 | byte[] bytes = BitConverter.GetBytes(n);
76 | if (!BitConverter.IsLittleEndian)
77 | {
78 | Util.Reverse(bytes);
79 | }
80 | return bytes;
81 | }
82 |
83 | //Get the byte length of message.
84 | public static int byteLength(string msg)
85 | {
86 | return System.Text.Encoding.UTF8.GetBytes(msg).Length;
87 | }
88 |
89 |
90 | }
91 | }
--------------------------------------------------------------------------------
/pomelo-dotnetClient/src/protobuf/MsgDecoder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using SimpleJson;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 |
7 | namespace Pomelo.Protobuf
8 | {
9 | public class MsgDecoder
10 | {
11 | private JsonObject protos { set; get; }//The message format(like .proto file)
12 | private int offset { set; get; }
13 | private byte[] buffer { set; get; }//The binary message from server.
14 | private Util util { set; get; }
15 |
16 | public MsgDecoder(JsonObject protos)
17 | {
18 | if (protos == null) protos = new JsonObject();
19 |
20 | this.protos = protos;
21 | this.util = new Util();
22 | }
23 |
24 | ///
25 | /// Decode message from server.
26 | ///
27 | ///
28 | /// Route.
29 | ///
30 | ///
31 | /// JsonObject.
32 | ///
33 | public JsonObject decode(string route, byte[] buf)
34 | {
35 | this.buffer = buf;
36 | this.offset = 0;
37 | object proto = null;
38 | if (this.protos.TryGetValue(route, out proto))
39 | {
40 | JsonObject msg = new JsonObject();
41 | return this.decodeMsg(msg, (JsonObject)proto, this.buffer.Length);
42 | }
43 | return null;
44 | }
45 |
46 |
47 | ///
48 | /// Decode the message.
49 | ///
50 | ///
51 | /// The message.
52 | ///
53 | ///
54 | /// JsonObject.
55 | ///
56 | ///
57 | /// JsonObject.
58 | ///
59 | ///
60 | /// int.
61 | ///
62 | private JsonObject decodeMsg(JsonObject msg, JsonObject proto, int length)
63 | {
64 | while (this.offset < length)
65 | {
66 | Dictionary head = this.getHead();
67 | int tag;
68 | if (head.TryGetValue("tag", out tag))
69 | {
70 | object _tags = null;
71 | if (proto.TryGetValue("__tags", out _tags))
72 | {
73 | object name;
74 | if (((JsonObject)_tags).TryGetValue(tag.ToString(), out name))
75 | {
76 | object value;
77 | if (proto.TryGetValue(name.ToString(), out value))
78 | {
79 | object option;
80 | if (((JsonObject)(value)).TryGetValue("option", out option))
81 | {
82 | switch (option.ToString())
83 | {
84 | case "optional":
85 | case "required":
86 | object type;
87 | if (((JsonObject)(value)).TryGetValue("type", out type))
88 | {
89 | msg.Add(name.ToString(), this.decodeProp(type.ToString(), proto));
90 | }
91 | break;
92 | case "repeated":
93 | object _name;
94 | if (!msg.TryGetValue(name.ToString(), out _name))
95 | {
96 | msg.Add(name.ToString(), new List