A simple C++/SDL_net chat server & client rewritten

Back in January this year I was due to be teaching some diploma level programming (roughly equivalent to the UK A/S level for any Brits), and part of that had to deal with network programming with sockets and stuff, so I duly did my research and put together a simple chat server and client in SDL_net. And then my classes changed and I got moved on to teach other stuff. I wasn’t too upset though – I’d learnt a lot, and I’d put up the code to help people out who might be in a similar situation, so it was all good.

But now in November I’m back on programming duty, so I dug up my code, looked it over, and thought Naah – I can’t use that, it’s unweildy, and complex, and it would be a real pain to try to re-use the code. So I’ve gone back to the drawing board and refactored it all into something I hope is a lot more palletable and both easy to use and re-purpose. In effect, I’ve refactored it into two wrappers which now consist of a ServerSocket class and a ClientSocket class.

Check it out…

Cross Platform Socket Server and Clients
Cross platform socket connectivity? That'll be a yes, then...

Socket Server

The old chat server was 250 lines, it’s now down to 77:

  1. // Re-written simple SDL_net socket server example | Nov 2011 | r3dux
  2. // Library dependencies: libSDL, libSDL_net
  4. #include <iostream>
  5. #include <string>
  6. #include <SDL/SDL_net.h>
  7. #include "ServerSocket.h"
  9. int main(int argc, char *argv[])
  10. {
  11. 	// Initialise SDL_net
  12. 	if (SDLNet_Init() == -1)
  13. 	{
  14. 		std::cerr << "Failed to intialise SDL_net: " << SDLNet_GetError() << std::endl;
  15. 		exit(-1);
  16. 	}
  18. 	// Create a pointer to a ServerSocket object
  19. 	ServerSocket *ss;
  21. 	try
  22. 	{
  23. 		// Try to instantiate the server socket
  24. 		// Parameters: port number, buffer size (i.e. max message size), max sockets
  25. 		ss = new ServerSocket(1234, 512, 3);
  26. 	}
  27. 	catch (SocketException e)
  28. 	{
  29. 		std::cerr << "Something went wrong creating a SocketServer object." << std::endl;
  30. 		std::cerr << "Error is: " << e.what()   << std::endl;
  31. 		std::cerr << "Terminating application." << std::endl;
  32. 		exit(-1);
  33. 	}
  35. 	try
  36. 	{
  37. 		// Specify which client is active, -1 means "no client is active"
  38. 		int activeClient = -1;
  40. 		// Main loop...
  41. 		do
  42. 		{
  43. 			// Check for any incoming connections to the server socket
  44. 			ss->checkForConnections();
  46. 			// At least once, but as many times as necessary to process all active clients...
  47. 			do
  48. 			{
  49. 				// ...get the client number of any clients with unprocessed activity (returns -1 if none)
  50. 				activeClient = ss->checkForActivity();
  52. 				// If there's a client with unprocessed activity...
  53. 				if (activeClient != -1)
  54. 				{
  55. 					// ...then process that client!
  56. 					ss->dealWithActivity(activeClient);
  57. 				}
  59. 			// When there are no more clients with activity to process, continue...
  60. 			} while (activeClient != -1);
  62. 		// ...until we've been asked to shut down.
  63. 		} while (ss->getShutdownStatus() == false);
  65. 	}
  66. 	catch (SocketException e)
  67. 	{
  68. 		cerr << "Caught an exception in the main loop..." << endl;
  69. 		cerr << e.what() << endl;
  70. 		cerr << "Terminating application." << endl;
  71. 	}
  73. 	// Shutdown SDLNet - our ServerSocket will clean up after itself on destruction
  74. 	SDLNet_Quit();
  76. 	return 0;
  77. }

Socket Client

And the old chat client was 313 lines, which is now down to 83:

  1. // Re-written simple SDL_net socket client example | Nov 2011 | r3dux
  2. // Library dependencies: libSDL, libSDL_net
  4. #include <iostream>
  5. #include <string>
  6. #include <SDL/SDL_net.h>
  8. #include "ClientSocket.h"
  10. int main(int argc, char *argv[])
  11. {
  12. 	// Initialise SDL_net (Note: We don't initialise or use normal SDL at all - only the SDL_net library!)
  13. 	if (SDLNet_Init() == -1)
  14. 	{
  15. 		std::cerr << "Failed to intialise SDL_net: " << SDLNet_GetError() << std::endl;
  16. 		exit(-1);
  17. 	}
  19. 	// Create a pointer to a ClientSocket object
  20. 	ClientSocket *cs;
  22. 	try
  23. 	{
  24. 		// Try to instantiate the client socket
  25. 		// Parameters: server address, port number, buffer size (i.e. max message size)
  26. 		// Note: You can provide the serverURL as a dot-quad ("") or a hostname ("server.foo.com")
  27. 		cs = new ClientSocket("", 1234, 512);
  28. 	}
  29. 	catch (SocketException e)
  30. 	{
  31. 		std::cerr << "Something went wrong creating a ClientSocket object." << std::endl;
  32. 		std::cerr << "Error is: " << e.what()   << std::endl;
  33. 		std::cerr << "Terminating application." << std::endl;
  34. 		exit(-1);
  35. 	}
  37. 	try
  38. 	{
  39. 		// Attempt to connect to the server at the provided address and port
  40. 		cs->connectToServer();
  42. 		string receivedMessage = "";
  44. 		cout << "Use /quit to disconnect or /shutdown to shutdown the server." << endl;
  46. 		// Display the initial prompt
  47. 		cs->displayPrompt();
  49. 		// Run the main loop...
  50. 		do
  51. 		{
  52. 			// Check if we've received a message
  53. 			receivedMessage = cs->checkForIncomingMessages();
  55. 			// If so then...
  56. 			if (receivedMessage != "")
  57. 			{
  58. 				// Display the message and then blank it...
  59. 				cs->displayMessage(receivedMessage);
  61. 				// ...and then re-display the prompt along with any typed-but-not-yet-sent input
  62. 				cs->displayPrompt();
  63. 			}
  65. 			// Get and deal with input from the user in a non-blocking manner
  66. 			cs->getUserInput();
  68. 		// ... until we decide to quit or the server is shut down
  69. 		} while ( (cs->getShutdownStatus() == false));
  71. 	}
  72. 	catch (SocketException e)
  73. 	{
  74. 		cerr << "Caught an exception in the main loop..." << endl;
  75. 		cerr << e.what() << endl;
  76. 		cerr << "Terminating application." << endl;
  77. 	}
  79. 	// Shutdown SDLNet - our ClientSocket will clean up after itself on destruction
  80. 	SDLNet_Quit();
  82. 	return 0;
  83. }

On top of all this we have try/catch exception handling, a nice encapsulated & easy to work-with/modify/extend design and debug flags to control whether the client/server should be verbose or run silently. Obviously the chat client itself can’t run completely silently – you wouldn’t be able to read the messages being sent back and forth! – but when debug is off it only ever outputs anything when it receives a message or when the user enters messages to send, so it’s pretty darn quiet.

Oh, and it now comes in Linux and Windows flavours =D

Overall I’m really happy with it – it’s taken a few days to properly redesign and test (not to mention the issues involved with porting to Windows) – but I think the next time I need to do some socket stuff with C++ I’d be able to grab this code, make whatever modifications I need and get something up and running in no time.

Awthome! =P

Download links

Notes on Building for Windows

The windows client and server projects have some important tweaks made for them to compile, and it’s worth mentioning what they are:

  • The solution (which contains two projects) comes comes with a copy of the SDL and SDL_net libs and headers all merged together in the SDL folder (well, there are separate libs and include folders, but all the headers from both are in the include folder and all the libs from both are in the libs folder).
  • Each project has the following libraries linked in: SDL.lib, SDLmain.lib and SDL_net.lib, these libraries point to…
  • SDL.dll and SDL_net.dll which are in the solution’s Debug folder, so you can compile and build from Visual Studio, BUT you’lll need to copy these two dll files into the same folder as the SocketServer-Rewritten.exe or SocketClient-Rewritten.exe folders to run the executables “standalone” in other locations as opposed to build-and-run-from-visual-studio style!
  • The projects are defined as console applications, and because SDLmain.lib defines the main function as int main(int argc, char *argv[]) and not just int main() you MUST keep the definition of main in-line with the SDLmain.lib definition.
  • Finally, the projects will only build successfully in debug mode. Why? I’ve no idea. If you know how to fix it then go for it!

41 thoughts on “A simple C++/SDL_net chat server & client rewritten”

    1. Glad ya like :D

      I did as much as I could to help you out with your specific requirements within the time I had available – I wish I’d have had this ready when it would have been of use to you, but such is life…

  1. That is really nice code, great job. It would fly through one of my code reviews without a single WTF!

    Clear and simple design
    Nice comments
    Exception handling

    ‘Nuff said :)

    1. Hehe – I love that comic =D

      Thanks for your kind comments – I worked really hard on it (did you know you can’t define structs in headers? I didn’t!). Just hope it makes socket programming more do-able for my students, and maybe anyone else trying to knock together some socket stuff!

      Really, the socket server has gone up from 250 to around 500 lines, and the client from 313 to around 600 lines. But I guess the payback comes when you can use it to actually do something useful in less than 100 lines of code, and modify and extend it with ease now that the mains are now almost purely “business logic”.

      Really happy with it =D

      1. Yes, absolutely.

        The term I believe you are scratching for is loosely coupled code.

        It takes longer to design and write code adhering to these principles, but the benefits are massive time savings down the line in the current project and/or future projects.

  2. for this time the coding is a bit different and weird( for me) because the ss and cs :D but the function is the same with the previous one. what type of coding u use to make it very simple..

    you are so nice sir.. however i’ve finish my presentation and of course using your code…the presentation went smoothly.. :) thanks a lot.. i will visit u more often to learn about coding and will never forget what u have teach me… i will remember u always..

  3. Nice job.
    I downloaded it and i’m actually enjoying ‘customizing’ it :)

    I have some problems when using BACKSPACE. Any idea for solving it?


    1. Hmm, you’ll prolly need to look for the ASCII code for backspace (8) in the getUserInput function and remove the last character from the message when you detect it.

      There’s also the issue of moving the text carat back one character, which you could get around by re-displaying the prompt each time, but that’s not very elegant. It’s all do-able, it just might be a little fiddly to nail it with a nice cross-platform solution.

      1. Tnx for the answer. Or probably storing temporarily the input using a simple scanf can be a nice solution.

        I was wondering if SDL can be used to create a socket to a client passing through a proxy. I did not find any documentation about it yet.

    1. You need the server to be running before you can connect with a client, so I assume you mean you’re getting the error “cannot bind to local port” when running the server.

      This could possibly be because something else is already running on port 1234, so try changing the port to something else, like 2012. For example:

      Server code change:

      ss = new ServerSocket(2012, 512, 3);

      Client code change:

      cs = new ClientSocket("", 2012, 512);

      Then, when you run the client (which you’ll need to do “standalone” if you’ve just run the server through Visual Studio [i.e. you’ll need to launch the client exe from windows explorer or the command line]) make sure you have the SDL.dll and SDL_net.dll files copied into the same location as the client executable, as it says in the Notes on building for WIndows section.

      Also, it just occurs to me that your firewall could, potentially, be blocking applications from opening ports, so you might want to try temporarily disabling it and trying again if the above doesn’t solve your problem.

      Hope this helps.

  4. Came across your revamped work while looking for serverless, P2P sample code – if you ever get motivated, or have to teach on this subject again, that would be a nice addition. – thank you for publishing your code. – Howard in Florida

  5. I have been looking for something like this for a couple of days and finally came across this. Thank you!
    I’m running openSUSE and managed to compile your older version with the information you gave Su here:


    I am relatively new to linux and could use some guidance on how to compile this version of your chat server.

    I tried: g++ -Wall `sdl-config –cflags –libs` -lpthread -lSDL -lSDL_net -o Server ./ServerSocket.cpp

    but these errors popped up:

    /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libpthread.so when searching for -lpthread
    /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libpthread.so when searching for -lpthread
    /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libSDL_net.so when searching for -lSDL_net
    /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libm.so when searching for -lm
    /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libc.so when searching for -lc
    /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../lib64/crt1.o: In function `_start’:
    /home/abuild/rpmbuild/BUILD/glibc-2.17/csu/../sysdeps/x86_64/start.S:119: undefined reference to `main’
    collect2: error: ld returned 1 exit status

    Is this a 64bit related error or am I just compiling it all wrong?

    1. These errors arise if i replace ServerSocket with Main:

      /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libpthread.so when searching for -lpthread
      /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libpthread.so when searching for -lpthread
      /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libSDL_net.so when searching for -lSDL_net
      /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libm.so when searching for -lm
      /usr/lib64/gcc/x86_64-suse-linux/4.7/../../../../x86_64-suse-linux/bin/ld: skipping incompatible /usr/lib/libc.so when searching for -lc
      /tmp/cc7HBV9E.o: In function `main’:
      Main.cpp:(.text+0x7c): undefined reference to `ServerSocket::ServerSocket(unsigned int, unsigned int, unsigned int)’
      Main.cpp:(.text+0x93): undefined reference to `ServerSocket::checkForConnections()’
      Main.cpp:(.text+0x9f): undefined reference to `ServerSocket::checkForActivity()’
      Main.cpp:(.text+0xb9): undefined reference to `ServerSocket::dealWithActivity(unsigned int)’
      Main.cpp:(.text+0xd0): undefined reference to `ServerSocket::getShutdownStatus()’
      collect2: error: ld returned 1 exit status

      1. You definitely need to compile the Main.cp, for any given project, but maybe you also need to tell g++ about ServerSocket.cpp.

        Okay, looking things up gives:

        g++ -Wall `sdl-config –cflags –libs` -lpthread -lSDL -lSDL_net -I. -o Server ./ServerSocket.cpp ./Main.cpp

        I don’t know if specifying the current directory with -I. will override the default /usr/lib/include folder for include files, if so you might need to have multiple -I switches.

        If there’s still “skipping incompatible” messages it seems to be a 32-bit/64-bit issue – so you might have the 32-bit version of some lib and the 64-bit version of another and you can’t mix and match – my Linux is 64-bit and I haven’t come across this issue.

        I’d still recommend you use an IDE rather than compile from the command line though, it’ll save you a ton of exactly this sort of grief! Get the Linux version of the project linked at the bottom of the post, install Code::Blocks, open the project and look under Project Properties | Build Options then check in the Linker settings tab look at the generic config (above Debug and Release in the top left corner) to see the list of libraries we’re linking against. Pick which libraries and locations through this and with any luck it’ll work.


        1. I tried to get codeblocks working on the 64bit os but ran into issues. So I downloaded the 32bit version of openSUSE and all works perfect now :) Thanks!

          Only issue I’m trying to resolve now is the server doesn’t display anything after i run it. It still receives and sends everything and shuts down but doesn’t list anything. Any ideas?

          1. Glad you got it working =D

            The ServerSocket is likely displaying nothing because the debug flag is set to false – just go into the ServerSocket.cpp file and flip it to true on line 11 then rebuild, the server should then spit out plenty of debug info about what data it’s transmitting and to which clients.

  6. Hey long time no talk! Reviewing somethings and trying to get the windows client to connect to the linux server that I’m running in virtualbox. How did you manage to do that?

    1. Hola =D I used the bridged adaptor setting on the virtual machine’s network adapter so that the vm was on the same subnet as the physical machine – once that’s done, they’ll just talk!

      Wrote a thing about it a long while ago, but all you need is the very 1st paragraph of this: http://r3dux.org/2009/09/how-to-make-virtualbox-use-your-routers-dhcp-to-get-an-ip-address-in-linux/.

      Works on any VirtualBox running platform, not just Linux (so article title is misleading – original method only worked on Linux).

      1. I thought that I just couldn’t get that to work. I tried it both on vmware workstation and virtualbox. After I change the settings to bridged network and update the ip with the one I found with ipconfig. I notice a change that the client gets to
        “Connection okay, about to read connection status from server.”
        before it closes. That actually only happens when I forward the same port I am using for the server. Without that port forwarding client just closes. Sometimes hangs when I experiment with ips saying that it couldn’t resolve hostname but will try because it technically has a valid ip.

        I am using the visual studio 8 express edition but both client and server work fine on windows alone so I don’t think that is the issue.

        1. So I did some testing. I am able to connect a linux client to a win server. However I can’t seem to do the opposite.

          it says ” Failed to resolve the server IP to hostname:
          Attempting to continue as we have a valid IP address…”

          I know this is an old topic and hate to be a pain but could you test linux server, win client just to see if I need to make additional changes to get this working.
          Appreciate the help.

            1. Going from a Linux server to Windows clients works fine for me – you just have to tell the clients the actual IP address of the server (not

              No idea why it’s not working for you, sorry…

              1. That is great news actually. It must be something with my router or network settings. I really appreciate you taking the time to test it out for me. I’ll try and figure it out. Cheers.

                1. Got it working. Silly me didn’t think to configure the firewall on openSUSE and allow the client to connect.

                  Now that I have that out of the way. Would it be difficult to make the client into a windows form instead of console?

    1. Good point. Shouldn’t limit myself, had no idea there were so many other options. Qt seems to offer everything I want so I’m going to give that a shot. I’ll watch some tuts tonight and see if I can implement it. Seems pretty straight forward and reminds me of my VB6 days so should be good. Thanks for the recommendation! Cheers.

  7. I’ve used your SDL networking tutorials to get my head around network programming for the first time. They have been incredibly helpful, I’ve based my code on your framework and extended it to use user commands and I’ve tested having other people connect over the internet and exchange messages. I’m currently adapting it to send data for a game project I am working on for a university class. We’re making a 3D dungeon crawler game similar to the like of Diablo, Torchlight etc. I’ll update you on the progress of my project. :)

    Your tutorials were great though, thanks for that! I might even write up one myself for my own site.

  8. Thanks for this very clear and useful code!
    I guess this server and client use a TCP protocol, but how could I turn it into a UDP protocol, in order to use it in multiplayer games for example?

    Thanks a lot!

  9. Thank you for creating this!

    About a month ago, I started developing a card game application that would be playable over the internet. I had no prior experience on network coding, so I needed a tutorial or a simple example application that I could reuse. I discovered this little programme and found it excellent, very easy to understand and, most importantly, nicely hackable.

    I basically reimplemented the user input in an SDL_Window and extended the chat part so that I could send both data and text messages in the same stream. Data messages are used internally to propose and declare changes to game state, and text messages are used for simple chatting. This is obviously rather slow (response times via TCP are typically 100–500 ms in my test scenarios) but since this card game is strictly turn-based and not fast-paced, it does not matter at all. I also had to code in means of disconnecting, reconnecting and recovering from an accidental disconnection, but those were quite straightforward to do once I understood how the code functions.

    I was eventually able to implement everything that I had planned, and the network part seems to work perfectly. I have no problem connecting computers running different operating systems and playing the game, although considering SDL’s extreme portability, that is very much expected.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.