|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionIn this article I hope to show a very useful architecture for building a network server over TCP/IP communication. Well enough chit-chat let's examine the problem: Sockets can use three modes for communicating: a. Synchronous communication - using the blockmode which halts execution until somthing happens in the socket. And offcourse it is possible to mix synchronus calls with asynchronous calls if you seriouly feel you don't The first examination is why and when would we want to use the async communition? Since async calls opens a thread for every socket operation it forms a great solution for client programs, So at our goals is to use the smallest amount of threads as long as our Latency definition (AKA: Lag) is meeting our design requirements. However, if for example I will connect to such a server from my client and I will decide not to send data to that server this would mean Another aproach would be to use Sync calls in blockmode to our sockets - this means that execution will halt, So to workaround this we can open a thread per client. But again we shall have many threads running in our system and that is somthing we already killed as a server solution. The last option remaining is to use the sync calls without blockmode. the problem is that 2000 clients connected to The remedy What I did in that point is creating a class which I called ServerNode, this ServerNode holds clients and return latency information When the server ClientsList recieves a new client the server scan all nodes and decide to which node to add the new client. Foreman Design Pattern - Is that a new design pattern ? (If not I got a new and very generic idea instead - I will call it the "Wheel"!). Well so far so good but while writing the code I couldn't help thinking that I somehow doing somthing which is very generic in many situations, I seeked the books and the internet to see if there is a known design pattern that actually do that - and found that there isn't so But... there is somthing that bothers me, what if some clients need diffrent latency than others ? hmm.. So scrathing my head I finally realized; Based on the Foreman Design Pattern I can build a very cool communication server. So, after building the foreman I begun with writing a simple code to wrap the socket communication options. I opened a project and called it NetworkSocketManager - that will be used in two other project, a server and a client. the NetworkSocketManager will let us choose between socketing work methodology and it wrap all Synchronic and Asynchronic communication options (including the block mode). Having done with that part, I coded a simple client that contains the NetworkSocketManager, The project is called NetworkClient. Now the client itself is also very nice & friendly since it already implements a basic application level transmition control, any data that is going to be sent is being warrped in an envelope which contains: If you wish to have encryption on your data - make sure to encrypt before you pass on the data to the send and if you wish to manipulate your message before sending it (for example if you need integration with anohter server) you will have to inherit the communication class and overide the communication functions to your needs. The next task was to build a server that uses the already mentioned ForemanDP, So... I opened another project and called it NetworkServer. in it I derived the ForemapDP worker class to CommunicationWorker class and server class derives from Foreman BasicServer. and walla. If everything so far is understood - you will be able to understand my code and why is it so powerful. The fact that this is a powerful code implentation lays in the fact that all the programmer needs to do is to derive a worker and a server to have an out of the box, running and opened sourced Client/Server architecture which uses a correct resource methodology. Comparing to Classic IOCP
As we can see the model based on the foreman will "milk" the machine better since the definition of required worker (client) latency has a meaning regarding who need more focus from the machine. to be even more exact, the clients that require latency < 100 are treated in a diffrent thread. Using the codeOk, So how do we get started? Step 1. The first thing is either to add just references or the projects into your solution. For those who need to have servers, You will need the NetworkSocketManager, ForemanDP & Network Server. For those who need to have clients, you will need the NetworkSocketManager & NetworkClient. For those who need both just add it all... Step 2. Server developers: private NetworkServerBase MyServer = null;
Next thing is to instanciate the server, you would want to put it in the Form_Load or a contsructor of your class: MyServer = new NetworkServerBase(new TimeSpan(1000)); // This line will add a hook for events in your class MyServer.OnServerNotify += new ForemanDP.BasicServer.DelegateServerNotification(MyServer_OnServerNotify); // Note that following line will not work becuase you need to replace the bolded area // with the ip you want to link. MyServer.AddListener( new NetworkServerClientListener(new TimeSpan(2000), new System.Net.IPEndPoint("replace this with the ip you want", 5500), 100)); The last line is intersting because what it actually does is adding a listener with a required latency of 2 secs to the server. The NetworkServerClientListener is derived from NetworkClientWorker which derives from ForemanDP worker. The line of code is setting port 5500 to be a listening port and put 100 backlog space for queue to clients which needs to connect. you can added more listeners - as many as you want! by running a loop on that line or just copy paste it, whatever your needs be. From that point forward every communication event to that port is piped to the MyServer_OnServerNotify: void MyServer_OnServerNotify(ForemanDP.BasicWorker worker, object data) { switch (((NetworkServerClientWorker.NetworkClientNotification)data).EventType) { case NetworkClient.NetworkClientBase.ClientEventTypeEnum.Accepted: connectedUsers++; break; case NetworkClientBase.ClientEventTypeEnum.Disconnected: connectedUsers--; break; } } You can catch messages and anything else you need from that event. Clients: In your class write your code to contain the NetworkClient: private NetworkClientBase clientCommunication = null; ---- your constuctor or Form_Load ----- clientCommunication = new NetworkClientBase( new CommunicationSettings( CommunicationSettings.SocketOperationFlow.Asynchronic, CommunicationSettings.SocketOperationFlow.Asynchronic, CommunicationSettings.SocketOperationFlow.Asynchronic, CommunicationSettings.SocketOperationFlow.Asynchronic, CommunicationSettings.SocketOperationFlow.Asynchronic, false, 64)); // and an event hooker! clientCommunication.OnClientEvent += new NetworkClientBase.DelegateClientEventMethod(clientCommunication_OnClientEvent); : : : --------------------------------------- //and then ... private void clientCommunication_OnClientEvent( NetworkClientBase.ClientEventTypeEnum EventType, object EventData) { switch (EventType) { case NetworkClientBase.ClientEventTypeEnum.None: break; case NetworkClientBase.ClientEventTypeEnum.Accepted: break; case NetworkClientBase.ClientEventTypeEnum.Connected: break; case NetworkClientBase.ClientEventTypeEnum.RawDataRecieved: break; case NetworkClientBase.ClientEventTypeEnum.MessageRecieved: break; : : : and so on to catch what ever you need or want. Latest Vesion Additional InfoAs an example I add a simple chat implementation, in order to run it correct: 1. Simply from visual studio click the green traingle button (F5) - this will run the chat server. 2. While the ChatServer is running go back to visual studio and right click on the ChatClient project - a popup menu will apear, from the popup-menu click Debug-Start New Instance. You can repeat step 2 to create and run as many instances as you want. Note: The chat-client/server is just an example for how to use the entire architecture, it is not the focus of this article and it is not intended to be bug-free. Benchmark program Addition The benchmark opens a server and multiple async clients to communicate with the server. Since it was neccary to identify each async client I created another client which contains a NetworkClientBase and adds Identity to it, normally you will not need such a client unless you want to work with multiple clients without a server or a main node to manage them inside it. FinallyMost of the programmers believe that they have the best code that only god may match in perfectness, And I am no diffrent! But in order to realy learn somthing one must put his ego very far away, So please let me know what you think and feel free to critisize. The connecter area in the server is not in use - I didn't finish it - but unless you want a server that can initate communication to other server like proxy for example, it will not bother you. I promise to finish it if you code project folks want it. Last thing: Some might ask why not to use WCF instead of all that ? WCF is a very advanced request-response architecture and as progressed as it is | ||||||||||||||||||||