forked from Q-Smith/.NET-MiniNet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Notes.txt
393 lines (328 loc) · 18.1 KB
/
Notes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/***********************************************************************************/
/* Low-Level Networking Library / Framework */
/***********************************************************************************/
Addressing Layer (Structuring and managing a multi-node network, including addressing, routing and traffic control)
- IPv4, IPv6, IPsec, ICMP
Transport Layer (Reliable transmission of data segments between points on a network, including segmentation, acknowledgement and multiplexing)
- InVM
- TCP
- UDP
Application or Session Layer (Managing communication sessions, i.e. continuous exchange of information in the form of multiple back-and-forth transmissions between two nodes)
- RS232?
- IPC (Named Pipes)
- HTTP
- FTP
- SMTP
- SSH
- DNS
- XMPP
- Websockets?
Data Layer (Translation of data between a networking service and an application; including character encoding, data compression and encryption/decryption)
- Text (ASCII / Unicode)
- Binary
Features
- encoding
- compression
- security (TLS, encryption/decryption)
- thread model (Single, Thread Pool, Multi-Pool)
- buffer management (traffic control)
- exception management
- message encoders and decoders
/***********************************************************************************/
/* High-Level Networking Library / Framework */
/***********************************************************************************/
Distributed Data Structures
- List
- Set
- Map / MultiMap
- Queue
- Topic
- Atomics
- Locks
- Semaphores
- Latches
- References (Weak / Strong)
Distributed Thread Executors
- Timers
- Threads
- Jobs
Distributed Events
Distributed Transactions
Cluster Management
- Node Discovery / Service Discovery
- Cluster Groups
/***********************************************************************************/
/* Messaging Library / Framework */
/***********************************************************************************/
MEP (Message Exchange Patterns)
- OneWay
- Request/Reply
- Publish/Subscribe
- Push/Pull (or visa-versa)
Messaging Transformations
- Pipes and Filters
- Message Router
- Message Splitter
- Message Expiration
Channels
- Point-to-Point Channel
- Publish-Subscribe Channel
- Invalid Message Channel
- Dead Letter Channel
Management
- Message Store
- Wire Tap
- Channel Purger
- Metrics
/***********************************************************************************/
/* My MiniNet Library */
/***********************************************************************************/
ISocket socket = MiniNet.CreateTcpSocket(options);
ISocket socket = MiniNet.CreateUdpSocket(options);
socket.Socket;
socket.Protocol;
socket.LocalEndPoint;
socket.RemoteEndPoint;
socket.Connect(endpoint)
socket.Connect(port, ip)
socket.Read(buffer);
socket.Write(buffer);
socket.Close(timeout);
IInVMListener listener = MiniNet.CreateInVMListener(options);
IInVMClient client = MiniNet.CreateInVMClient(options);
ITcpListener listener = MiniNet.CreateTcpListener(options);
ITcpClient client = MiniNet.CreateTcpClient(options);
IUdpListener listener = MiniNet.CreateUdpListener(options);
IUdpClient client = MiniNet.CreateUdpClient(options);
IHttpServer server = MiniNet.CreateHttpServer(options);
IHttpClient client = MiniNet.CreateHttpClient(options);
IFtpServer server = MiniNet.CreateFtpServer(options);
IFtpClient client = MiniNet.CreateFtpClient(options);
DnsClient dns = MiniNet.CreateDnsClient(options);
dns.lookup("vertx.io", ar -> {}); // Try to lookup the A (ipv4) or AAAA (ipv6) record for a given name.
dns.lookup4("vertx.io", ar -> {}); // Try to lookup the A (ipv4) record for a given name.
dns.lookup6("vertx.io", ar -> {}); // Try to lookup the AAAA (ipv6) record for a given name.
dns.resolveA("vertx.io", ar -> {}); // Try to resolve all A (ipv4) records for a given name.
dns.resolveAAA("vertx.io", ar -> {}); // Try to resolve all AAAA (ipv6) records for a given name.
dns.resolveCNAME("vertx.io", ar -> {}); // Try to resolve all CNAME records for a given name.
dns.resolveMX("vertx.io", ar -> {}); // Try to resolve all MX records for a given name.
dns.resolveTXT("vertx.io", ar -> {}); // Try to resolve all TXT records for a given name.
dns.resolveNS("vertx.io", ar -> {}); // Try to resolve all NS records for a given name.
dns.resolveSRV("vertx.io", ar -> {}); // Try to resolve all SRV records for a given name.
dns.resolvePTR("1.0.0.10.in-addr.arpa", ar -> {}); // Try to resolve the PTR record for a given name.
/***********************************************************************************/
/* Open Source Libraries / Frameworks */
/***********************************************************************************/
====
.NET
====
https://github.com/zeromq/netmq (NetMQ is a 100% native C# port of the lightweight messaging library ZeroMQ)
https://github.com/longshine/Mina.NET (.NET port of Apache MINA.)
https://github.com/NModbus4/NModbus4 (NModbus is a C# implementation of the Modbus protocol)
http://www.eneter.net/ (Cross-platform framework for interprocess communication)
https://github.com/titantse/netty.net (.NET port of Netty.)
https://github.com/helios-io/helios (Helios is concurrency and networking middleware for .NET - think of it as a loose C# port of Java's wildly influential Netty library)
https://github.com/statianzo/Fleck (Fleck is a WebSocket server implementation in C#.)
https://github.com/jlmessenger/NetSocket
https://github.com/ironyx/simplsockets
https://github.com/mtmk/ProtobufSockets
https://github.com/UnitedTraders/SocketSlim
https://github.com/safakgur/Dawn.SocketAwaitable
https://github.com/Jiddler/Hyperletter
https://github.com/lidgren/lidgren-network-gen3
====
Java
====
http://hazelcast.org/ (Open Source In-Memory Data Grid)
http://netty.io/ (Netty is an asynchronous event-driven network application framework)
https://mina.apache.org/ (Apache MINA is a network application framework which helps users develop high performance and high scalability network applications easily.)
http://vertx.io (Vert.x is a tool-kit for building scalable reactive applications on the JVM)
==============
Research Links
==============
https://github.com/jbogard/MediatR/wiki
https://channel9.msdn.com/blogs/bruceky/how-to-parallelize-your-application-part-1-why-do-it
http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod
http://www.ahuwanya.net/blog/post/Buffer-Pooling-for-NET-Socket-Operations
http://simplygenius.net/Article/AncillaryAsyncProgress
http://blog.cincura.net/233459-wrapping-event-based-asynchronous-pattern-eap-into-task-based-asynchronous-pattern-tap/
http://stackoverflow.com/questions/869744/how-to-write-a-scalable-tcp-ip-based-server
http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
https://github.com/jacoblusk/SAEA-HTTPD/blob/master/SAEA-HTTPD/HttpServer.cs
https://github.com/EventStore/EventStore/blob/master/src/EventStore.Transport.Tcp/TcpConnection.cs
https://github.com/bcuff/MemcachedSharp/blob/master/src/MemcachedSharp/SocketExtensions.cs
/***********************************************************************************/
/* Troubleshooting */
/***********************************************************************************/
(1)
- The requested address is not valid in its context 0.0.0.0:8080
- Change from IPAddress.Any to IPAddress.Loopback, or specify the computers IP Address.
/***********************************************************************************/
/* Sockets */
/***********************************************************************************/
/======================================/
/ Basics /
/======================================/
A socket is like a "handle" to a port which allows us to access data sent to that port.
There are four main steps in using a socket server with TCP:
1.) Listen for connection requests on the server.
The client machine's Windows TCP/IP subsystem will automatically assign an outgoing port to the socket on the client machine.
It will contact the server by sending a SYN packet which is addressed to the socket server's IP address and port number.
After a client initiates a connection on the server's listening socket, the Windows TCP/IP subsystem of the server will respond with SYN, ACK.
Then the client machine's Windows TCP/IP subsystem responds back with an ACK packet.
When the ACK is received by the server, the "handshake" is complete, and the connection is established.
Windows will handle this TCP/IP protocol stuff for you.
In other words, SYN, ACK, PSH, packets, and similar parts of TCP/IP protocol do not have to be coded by you.
The server's listening socket can maintain a queue of connection requests waiting to be accepted.
This queue is called the "backlog". The listening socket passes the connection info to another socket via an "accept" operation,
and then gets the next incoming connection in the backlog queue, or if there is none, waits till there is a new connection request from a client.
2.) Accept connection requests
In order to have multiple connections on the same port, the server's listening socket must pass off the connection info to another socket,
which accepts it. The accepting socket is not bound to the port. You post an accept operation to pass the connection from the listening socket
to the accepting socket. The client does not need to perform an accept operation.
3.) Receive/Send via the connection
After the accept operation has completed, you can now receive or send data with that connection.
"Receive" is also known as "read". "Send" is also referred to as "write".
4.) Close the connection
Either client or server can initiate an operation to close the connection.
Usually, the client would initiate that. Again, the lower level TCP/IP of the disconnect is handled by the Windows Operating System.
The connection can be closed using the Close method, which destroys the Socket and cleans up its managed and unmanaged resources.
With TCP, there is no guarantee that one send operation on the client will be equal to one receive operation on the server.
One send operation on the client might be equal to one, two, or more receive operations on the server.
And the same is true going back to the client from the server.
This peculiarity can be due to buffer size, network lag, and the way that the Operating System handles TCP to improve performance.
So you must have some way of determining where a TCP message begins and/or ends.
Three possible ways to handle TCP messages are:
1.) Prefix every message with an integer that tells the length of the message.
2.) All messages be fixed length. And both client and server must know the length before the message is sent.
3.) Append every message with a delimiter to show where it ends. And both client and server must know what the delimiter is before the message is sent.
/======================================/
/ I/O Completion Ports (IOCP) /
/======================================/
Microsoft created the SocketAsyncEventArgs class to help you write scalable, high performance socket server code.
SocketAsyncEventArgs uses I/O Completion Ports via the asynchronous methods in the .NET Socket class.
Why create a pool of the SocketAsyncEventArgs class?
The pool for receive/send operations should probably be at least equal to the maximum number of concurrent connections allowed.
/======================================/
/ Communication Protocol /
/======================================/
What is our communication protocol in this code?
1.) We will prefix every message with an integer that tells the length of the message.
2.) One message from client will correspond with one message from the server.
3.) After a connection is made, the client will send a message first, and then post a receive op to wait for the response from the server.
And for each message that the client sends, the server will respond with a message to the client.
/======================================/
/ TCP Buffers /
/======================================/
Buffers in TCP are unmanaged, that is, not controlled by the .NET Framework, but by the Windows system.
So the buffer gets "pinned" to one place in memory, thereby causing memory fragmentation, since the .NET Garbage Collector
will not be able to collect that space. This situation is improved by putting all the buffers together in one block of memory,
and just reusing that same space over and over. Also from what I remember is that the .NET Garbage Collector
is a compacting collector and memory fragmentation will hurt any GC operations.
The theoretical maximum size for the buffer block is (2^31 = 2.147 GB), since it uses an integer data type.
For example, if you use a buffer size of 50,000 bytes, and have a separate buffer for send and receive, then that is 100,000 bytes per connection.
2.147 GB divided by 100,000 bytes = 21,470, which would be the maximum number of concurrent connections that could use this
buffer block with this buffer size and design.
Still To Discuss
----------------
See: http://www.winsocketdotnetworkprogramming.com/clientserversocketnetworkcommunication8d.html
.) Whare does "NoDelay" do?
.) What does "LingerState" do?
.) What does [SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true)] do?
Framing:
Framing Messages in Streams
/***********************************************************************************/
/* Java to C# */ (http://www.25hoursaday.com/CsharpVsJava.html)
/***********************************************************************************/
/======================================/
/ Interfaces /
/======================================/
Code against the Interface for all Public and Protected methods and/or properties.
Code against the Concrete Class for all Private methods and/or properties.
/======================================/
/ Asynchronous Programming Patterns /
/======================================/
Ref: https://msdn.microsoft.com/en-us/library/jj152938(v=vs.110).aspx
1.) Asynchronous Programming Model (APM).
2.) Event-based Asynchronous Pattern (EAP).
3.) Task-based Asynchronous Pattern (TAP).
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx (See Deadlock Demo)
http://simplygenius.net/Article/AncillaryAsyncProgress
From APM to TAP
---------------
Consider the Stream class and its BeginRead/EndRead methods, which represent the APM counterpart to the synchronous Read method:
APM:
public int Read(byte [] buffer, int offset, int count);
public IAsyncResult BeginRead(byte [] buffer, int offset, int count, AsyncCallback callback, object state);
public int EndRead(IAsyncResult asyncResult);
TAP (Option 1):
public static Task<int> ReadAsync(this Stream stream, byte [] buffer, int offset, int count) {
if (stream == null) throw new ArgumentNullException("stream");
return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, null);
}
TAP (Option 2):
public static Task<int> ReadAsync(this Stream stream, byte [] buffer, int offset, int count) {
if (stream == null) throw new ArgumentNullException("stream");
var tcs = new TaskCompletionSource<int>();
stream.BeginRead(buffer, offset, count, cb_iar => {
try { tcs.TrySetResult(stream.EndRead(cb_iar)); }
catch(OperationCanceledException) { tcs.TrySetCanceled(); }
catch(Exception exc) { tcs.TrySetException(exc); }
}, null);
return tcs.Task;
}
From EAP to TAP
---------------
To demonstrate, the following code wraps the DownloadStringAsync method.
DownloadStringAsync accepts a URI, raises the DownloadProgressChanged event while downloading in order to
report multiple statistics on progress, and raises the DownloadStringCompleted event when it's done.
TAP:
public static Task<string> DownloadStringAsync(Uri url) {
var tcs = new TaskCompletionSource<string>();
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, eventArgs) => {
if (eventArgs.Error != null) tcs.TrySetException(eventArgs.Error);
else if (eventArgs.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(eventArgs.Result);
};
wc.DownloadStringAsync(url);
return tcs.Task;
}
Think Continuations, not Callbacks
----------------------------------
Ref: http://reedcopsey.com/2010/04/19/parallelism-in-net-part-17-think-continuations-not-callbacks/
Await and Await
---------------
How to capture exceptions:
ExceptionDispatchInfo capturedException = null;
try {
await Socket.AcceptAsync();
} catch (Exception ex) {
capturedException = ExceptionDispatchInfo.Capture(ex);
}
if (capturedException != null) {
capturedException.Throw();
}
/======================================/
/ Memory /
/======================================/
Memory Limits
-------------
http://bhrnjica.net/2012/07/22/with-net-4-5-10-years-memory-limit-of-2-gb-is-over/
The Microsoft CLR has a 2GB maximum object size limit, even the 64 bit version.
From 4.5 onwards you can allocate larger objects if gcAllowVeryLargeObjects is enabled.
This feature works only with 64bit OS, it will not work with 32 bit.
Memory Pinning (Heap Fragmentation)
--------------
http://www.ahuwanya.net/blog/post/Buffer-Pooling-for-NET-Socket-Operations
/======================================/
/ Mappings /
/======================================/
java.nio.ByteBuffer -> System.IO.MemoryStream
/***********************************************************************************/
/* MiniNet Example */
/***********************************************************************************/
/***********************************************************************************/
/* References & Acknowledgements */
/***********************************************************************************/
http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod