• Advertisement
Sign in to follow this  


This topic is 2625 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've developed this library to replace the existing net code in SquareSpace. It's basically a wrapper for WinSock that makes communicating between client and servers in multiplayer games a lot faster and simpler.

You can browse the source code here: http://e-network.goo....com/svn/trunk/
Or visit the project page here: http://code.google.com/p/e-network/

I've only completed the initial version tonight after starting it a few hours ago so there's a lot to add and change, but the infrastructure is there and it works nicely.

Messages are handled by various virtual functions (OnMessageRecieved,OnClientConnection) to allow the client/server to control information flow. The library acts as a connection manager and notification dispatcher.

Example server inherited OnMessageRecieve/OnClientConnect functions:

ENvoid EN_MessageNotifyServer::OnMessageRecieve( ENenum index, EN_MessageIn * msg )
ENenum eMID = msg->ArgI( 0 );
ENenum eCount = msg->GetArgCount( );

/* Must have at-least one argument */
if( eCount < 1 )

switch( eMID )
/* Client has disconnected */

enRemoveClientConnection( index );

/* Send the message ID back to the remaining clients */
EN_MessageOut * eMessage = new EN_MessageOut( eMID );

/* If Disconnection reason specified */
if( eCount == 2 )
/* Write the connection reason into the packet */
eMessage->WriteString( msg->ArgS( 1 ) );

/* Dispatch the message but ignore the client that sent the message */
enDispatchMessageToAllClients( index, eMessage );

delete eMessage;


ENvoid EN_MessageNotifyServer::OnClientConnect( en_client_s * client )
/* Tell the client that connection was accepted */
EN_MessageOut * eMessage = new EN_MessageOut( EN_MID_CONNECTIONOK );

EN_WRAP( enDispatchMessageToClient( client->m_Index, eMessage ) );

delete eMessage;
If you notice anything that needs changing then let me know. I'll keep updating the source every now-and-then.

I'm open to criticism/ideas/whatever.


Share this post

Link to post
Share on other sites
I'm going to give you some constructive criticism while trying my best to not make it sound like I'm just trying to crush your project. ;) I'm just going to make a list and elaborate on the points to avoid making this one tl;dr reply. So when reading these, please keep that in mind, I'm not trying to bash your work!

1. The mechanics of TCP are being misued. TCP is a stream protocol but you are using it like a packet protocol. In short, you must build and maintain the stream of data sent or received and perform sliding window operations to ensure all data is sent/received as needed. For example, any place you call send, you need to compare the number of bytes sent to the size of the data being sent. If it's not equal, as it can be less depending on the current TCP state, you need to perform another send operation to ensure it's sent in order. Likewise with recv, you need to store the entire stream, then parse out whole messages rather than treating them as individual messages.

2. The code is not thread safe. While it does not have to be, I've yet to see any mention of that fact. For really robust, reusable network code, you should consider thread support. While implementing thread safety is no easy task, it's also pretty important since it's easy to have a situation where code gets called from different threads, most notably GUI applications.

3. Consider using portable types rather than redefining all types for yourself. Platform portability between 32 and 64-bits might not be a high priority on your todo list, but as soon as you have the need or someone else does who wants to use your code, going back and trying to add it after the fact is a nightmare. The reason you want to use portable types as well is for any cross platform endeavors as well. While your code looks to be targeting solely Windows right now, you might have the need to go back and change that. Coding without that in mind also makes changes later on a nightmare.

4. The C/C++ style of coding and various things makes the library look and feel really awkward. It's more C with little C++ constructs being used rather than C++ with a little C constructs being used. The difference between the two is the former is more restrictive while the latter is more flexible. For example, why code in physical limitations such as EN_MAX_CLIENTS when you can just have use a vector and allow it to change at run-time without having to recompile a ton of code? I.e., you can just reserve a bunch of elements as you need upfront, emulating the C array then use push_back and erase freely without allocation hits since the memory is already there.

5. The global objects for the client / server objects are really design hampering. What If I needed more than one server object in a program or more than one client object? This point also goes into the previous one about the C/C++ code mixture. Trying to implement threading or object reuse is simply not possible when you do these things. For example, the EN_MessageOut class uses the g_sOutPacket object. This means you cannot have more than one EN_MessageOut object at once.

6. You are using a text based protocol over TCP. This is a huge deal breaker for a lot of people just because of how inefficient it can be unless optimized.The use of your delimiters can lead to other problems as well if binary data needs to be sent or if the text data contains that delimiter. What you need to do is implement a specific style of encoding like the HTTP uses to avoid that issue. So if I wanted to send "test\r\btest", then you'd convert the \r and \n before simply adding it to the message and sending it. The biggest problem I want to point out with this though is your protocol is coupled to the raw networking layer which is really restrictive and makes code reuse across different projects hard.

7. The design of the network code does not use select, so it will be very CPU intensive and inefficient. There are many alternative ways to avoid this so this is a high priority problem to be fixed.

8. Memory leaks. There are quite a few. Consider using more C++ stuff to address these, such as auto_ptr or boost::shared_ptr. Speaking of memory management, given you are explicitly calling new and delete for a lot of things, you can consider if you really need to do that or not. For example, the code where you allocate, call a function, then call delete, you can just use the stack instead. You don't need to add that extra overhead in those cases ( I do not consider this a micro optimization as much as a design flaw ).

Those are just the main points I want to bring up now. I've spent the better part of 3 years now constantly writing and rewriting TCP networking libraries to try and find a solution that can easily cater towards any generic use. After spending so much time trying to write my own core network library, i finally gave up and decided to use boost::asio as the core instead. In doing so, I went from having a 1200+ LOC networking library to having one that was right at 300. Not only that, it was much easier to maintain and understand since boost took care of so much.

So my advice nowadays to anyone trying to work with TCP and is able to use C++, use boost::asio. Some people might call it overkill for some tasks, but you are making a future investment into learning a very powerful and flexible library that is cross platform, allows for 32 and 64bit compilation, and uses a very flexible model for async or sync networking operations. There is a learning curve to it that takes some time. Learning advanced C++ stuff that boost uses is not easy, but it will make you a better programmer once you learn how to use the tools the right way and allow you to code in ways you didn't think was possible before.

There are certain trade offs to understand when using boost::asio though. At the expense of general overhead and memory usage, you are getting code that is flexible and allows you to minimize the amount of work you have to do to implement traditional networking designs. As a result, your code is much smaller and easier to maintain all the while being able to support some cool features that if you wanted to code yourself would take quite some time. So, that's it for my boost::asio pitch, I think it's invaluable to use as core code and then implement your own protocol on top of it once you have your own core library wrapper done for it.

On that note, I noticed you are using Visual Studio 7.1. Depending on your projects, you should consider the free 2008 or 2010 EE which have a lot of fixes to stuff since then. You can read up on changes made since, but unless you absolutely have to program in it, I think it'd be a good idea to start getting accommodated to a higher version. Just my own opinion though as a programmer. You will really want to make that consideration if you are going to use boost!

Anyways, hope this helps some, good luck with your project!

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement