Here's a standalone C# 4.0 app that demonstrates how to setup a TCP/IP sockets based client and server in .NET. It uses a command line option to determine whether to run the client or server. There's no external files or libraries needed, just the standard ones you get with a C# 4.0 console project. I've tested it with Visual Studio 2010 in Windows, and it will also work unchanged with Mono.
To run the server, from the command prompt...
SocketsTest -server
To run the client, from another command prompt ...
SocketsTest -client
Below is the source code ...
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; ////// Standalone TCP/IP sockets example using C#.NET 4.0 /// ////// Compile as a C#.NET console mode application /// /// Command line usage: /// SocketsTest -client => run the client /// SocketsTest -server => run the server /// class SocketsTest { static TcpListener listener; // Sample high score table data static Dictionary<string, int> highScoreTable = new Dictionary<string, int>() { { "john", 1001 }, { "ann", 1350 }, { "bob", 1200 }, { "roxy", 1199 } }; static int Port = 4321; static IPAddress IP_ADDRESS = new IPAddress(new byte[] { 127, 0, 0, 1 }); static string HOSTNAME = "127.0.0.1"; static int MAX_CLIENTS = 5; public static void Main(string[] args) { if (args.Contains("-server")) { ServerMain(); } else if (args.Contains("-client")) { ClientMain(); } else { Console.WriteLine("Usage: SocketsTest -client => run the client"); Console.WriteLine(" SocketsTest -server => run the server"); } } ////// Server receives player name requests from the client and responds with the score. /// private static void ServerMain() { listener = new TcpListener(IP_ADDRESS, Port); listener.Start(); Console.WriteLine("Server running, listening to port " + Port + " at " + IP_ADDRESS); Console.WriteLine("Hit Ctrl-C to exit"); var tasks = new List(); for (int i = 0; i < MAX_CLIENTS; i++) { Task task = new Task(Service, TaskCreationOptions.LongRunning); task.Start(); tasks.Add(task); } Task.WaitAll(tasks.ToArray()); listener.Stop(); } private static void Service() { while (true) { Socket socket = listener.AcceptSocket(); Console.WriteLine("Connected: {0}", socket.RemoteEndPoint); try { // Open the stream Stream stream = new NetworkStream(socket); StreamReader sr = new StreamReader(stream); StreamWriter sw = new StreamWriter(stream); sw.AutoFlush = true; sw.WriteLine("{0} stats available", highScoreTable.Count); while (true) { // Read name from client string name = sr.ReadLine(); if (name == "" || name == null) break; // Write score to client if (highScoreTable.ContainsKey(name)) sw.WriteLine(highScoreTable[name]); else sw.WriteLine("Player '" + name + "' was not found."); } stream.Close(); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Disconnected: {0}", socket.RemoteEndPoint); socket.Close(); } } /// /// Client requests a player name's score from the server. /// private static void ClientMain() { TcpClient client = new TcpClient(HOSTNAME, Port); try { // Open the stream Stream stream = client.GetStream(); StreamReader sr = new StreamReader(stream); StreamWriter sw = new StreamWriter(stream); sw.AutoFlush = true; // Read and output the first line from the service, which // contains the number of players listed in the table. Console.WriteLine(sr.ReadLine()); while (true) { // Input player name Console.Write("Enter player name: "); string name = Console.ReadLine(); // Write name to server sw.WriteLine(name); if (name == "") break; // Read score from server Console.WriteLine(sr.ReadLine()); } stream.Close(); } finally { // Close the connection client.Close(); } } }
Follow @dodgy_coder
Subscribe to posts via RSS
This is a great simple example! It really helped me to better understand how to create a simple client-server application. Thanks! :)
ReplyDeleteHi Derek, you're welcome, glad you found it useful. Out of interest this will also work unchanged on a Linux machine running via the Mono runtime. I have also recently tried it on a Raspberry Pi single board computer running under Debian linux.
DeleteI'm developing a Windows Form that executes some of these functions in a Background Worker, but for some reason, the Worker seems to be timing out. Have you worked with TCP/IP as a Background Worker before?
ReplyDeleteYes I have client code similar to the above running in a BackgroundWorker (from inside a WPF app) ... and haven't had any timeout problems. It sounds like your problem might be with the TCP/IP server side or a connection issue rather than the background worker itself?
DeleteHi,
ReplyDeleteI am getting an error..."The type or namespace 'task' could not be found(are you missing a using directive or an assembly reference?)
I believe I have all the proper using statements. Could you please assist?
I am thinking that I should be having a Class defining task, so that I can create the List, as in - var tasks = new List(); -
DeleteIs this the correct assumption. Could you please advise?
I want to create a TCP server that listens to multiple clients and I think if I could use your code as a starting point I can achieve that. Please assist.
Hi Onsongo, yes I believe you can use this code as a starting point for your project ... it definitely handles multiple clients. Regarding the message about the 'Task' class ... the 'Task' class is found in the .Net 4.0 assemblies and should be already referenced from a .Net 4.0 console application project. Are you using visual studio 2010 with .net 4.0? Or another environment?
DeleteThank you for your reply.
DeleteI actually solved the problem by referencing the System.Threading.Tasks.dll explicitly, from the C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5 folder. Incidentally, I am using .NET 4.5 Framework (VS 2012).
I also noticed that I was using task instead of Task in my declaration. Silly me, I was not looking carefully at the code.
I am sure now that i can move forward from here.
Thanks again for you reply. It gave me an idea on how to resolve this.
Kind Regards,
Onsongo Moseti.
Hello Dodgy,
ReplyDeleteDo you happen to have a version of this program that allows the server to handle multiple clients? I have seen plenty of bad examples out there but not a single good one yet!
Thanks,
Sainey
This will work with multiple clients ... check out the MAX_CLIENTS constant (currently set to 5) ... I admit, this isn't the most efficient nor elegant code out there, but it works, AFAIK :-)
DeleteNice!
ReplyDeleteI know you're not updating the dictionary anywhere, but perhaps you should consider ConcurrentDictionary to avoid concurrency issues, and while you're at it, use TryGetValue to get the value while checking for it.
What would you do if it was a chat server with thousands of clients? Do you have a sample for something like that ?
ReplyDeleteTheoretically it should be able to handle it ... just set the MAX_CLIENTS value to 1000 or whatever your limit is. I haven't tried it though. You might also want to take a look at golang or node.js, which might be better suited to your project.
DeleteC# multi threaded socket programming
ReplyDeletehttp://csharp.net-informations.com/communications/csharp-multi-threaded-socket.htm
ling
Had to change this line:
ReplyDeletevar tasks = new List<Task>();
Then it complies and works well.
Thanks
Oops, well spotted, thanks!
DeleteThanks, I have been looking for something like this for a while! Brian
ReplyDeletegreat
ReplyDelete