In this tutorial I'm going to show you how to build a threaded tcp server with C#. If you've ever worked with Window's sockets, you know how difficult this can sometimes be. However, thanks to the .NET framework, making one is a lot easier than it used to be.
What we'll be building today is a very simple server that accepts client connections and can send and receive data. The server spawns a thread for each client and can, in theory, accept as many connections as you want (although in practice this is limited because you can only spawn so many threads before Windows will get upset).
Let's just jump into some code. Below is the basic setup for our TCP server class.
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace TCPServerTutorial
{
class Server
{
private TcpListener tcpListener;
private Thread listenThread;
public Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
}
}
So here's a basic server class - without the guts. We've got a TcpListener which does a good job of wrapping up the underlying socket communication, and a Thread which will be listening for client connections. You might have noticed the function ListenForClients that is used for our ThreadStart delegate. Let's see what that looks like.
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
This function is pretty simple. First it starts our TcpListener and then sits in a loop accepting connections. The call to AcceptTcpClient will block until a client has connected, at which point we fire off a thread to handle communication with our new client. I used a ParameterizedThreadStart delegate so I could pass the TcpClient object returned by the AcceptTcpClient call to our new thread.
The function I used for the ParameterizedThreadStart is called HandleClientComm. This function is responsible for reading data from the client. Let's have a look at it.
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
}
tcpClient.Close();
}
The first thing we need to do is cast client as a TcpClient object since the ParameterizedThreadStart delegate can only accept object types. Next, we get the NetworkStream from the TcpClient, which we'll be using to do our reading. After that we simply sit in a while true loop reading information from the client. The Read call will block indefinitely until a message from the client has been received. If you read zero bytes from the client, you know the client has disconnected. Otherwise, a message has been successfully received from the server. In my example code, I simply convert the byte array to a string and push it to the debug console. You will, of course, do something more interesting with the data - I hope. If the socket has an error or the client disconnects, you should call Close on the TcpClient object to free up any resources it was using.
Believe it or not, that's pretty much all you need to do to create a threaded server that accepts connections and reads data from clients. However, a server isn't very useful if it can't send data back, so let's look at how to send data to one of our connected clients.
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Client!");
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.Flush();
Do you remember the TcpClient object that was returned from the call AcceptTcpClient? Well, that's the object we'll be using to send data back to that client. That being said, you'll probably want to keep those objects around somewhere in your server. I usually keep a collection of TcpClient objects that I can use later. Sending data to connected clients is very simple. All you have to do is call Write on the the client's NetworkStream object and pass it the byte array you'd like to send.
Your TCP server is now finished. The hard part is defining a good protocol to use for sending information between the client and server. Application level protocols are generally unique for application, so I'm not going to go into any details - you'll just have to invent you're own.
But what use is a server without a client to connect to it? This tutorial is mainly about the server, but here's a quick piece of code that shows you how to set up a basic TCP connection and send it a piece of data.
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Server!");
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.Flush();
The first thing we need to do is get the client connected to the server. We use the TcpClient.Connect method to do this. It needs the IPEndPoint of our server to make the connection - in this case I connect it to localhost on port 3000. I then simply send the server the string "Hello Server!".
One very important thing to remember is that one write from the client or server does not always equal one read on the receiving end. For instance, your client could send 10 bytes to the server, but the server may not get all 10 bytes the first time it reads. Using TCP, you're pretty much guaranteed to eventually get all 10 bytes, but it might take more than one read. You should keep that in mind when designing your protocol.
That's it! Now get out there and clog the tubes with your fancy new C# TCP servers. As always, comments and questions are welcome.
11/02/2007 - 13:04
I searched a lot for a simple article in tcp reading / writting.
After googling with several alternatives i found this page.
Simply Good & simple.
- Thx.
07/13/2009 - 12:50
Check MSDN they have a great example.
11/07/2007 - 08:52
Yep, it's very simple if you're writing a console application.
Try making a chat with with .NET sockets and you'll figure out there are no events support :-/
unlike VB6 with Winsock :)
11/07/2007 - 09:15
Can you elaborate on the events support? A few years ago a couple of us built a simple chat application using the framework above without any issues.
11/08/2007 - 02:17
Hi again :)
Well, if you need to make a chat like application you have to use a non-blocking sockets right ? so you use async methods (BeginReceive/EndReceive BeginConnect/EndConnect etc) but the problem is the once you received some data or got connected, you're AsyncCallback is fired and you're on a seperate thread ! so you have to Invoke the mothods for the GUI's thread to know you've received some data :-/
But how can you invoke a method if you're a "pure" class and not a control with a parent control to call the Invoke method?
That's the way i see it, but maybe I'm wrong :)
I'de like to know what you think!
Mas-Tool
11/08/2007 - 09:24
I don't really like using the Async callbacks so I opted for a blocking socket sitting on its own thread. When a message was received, I would then fire an event out of the "pure" class that can be caught by a higher level control. My event handler would contain the message that was received. The control would then invoke a method to display the message to the GUI.
That's the architecture I like to follow, but of course it won't work for every application.
02/22/2010 - 11:20
hi
mybe it`s so funy but where is the main method to start
compiling for this program and , where is the place of
final code(code before client code)in this program.
12/01/2007 - 08:08
A little parse error in your client program:
new IPEndPoint(IPAddress.Parse("127.0.0.1", 3000);
Needs to be:
new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
12/01/2007 - 09:23
Good catch. I've corrected the post.
01/15/2008 - 07:20
Very good tutorial. clear and simple.
thanks a lot
02/06/2008 - 05:42
I am searching for windows version of it,it is too simple for beginers
02/09/2008 - 05:08
Anybody know how to connect via internet?
PC1->routerA->internet->routerB->PC2
02/11/2008 - 14:31
is there a simple version of this for .net 1.1? specifically with regards to closing the connection releasing client resources to be able to use them again, the next time a connection comes in...
02/19/2008 - 19:03
Is there a particular reason for starting a thread in the constructor? As far as I can tell there would be no difference just calling ListenForClients() and it creates its own threads.
02/19/2008 - 20:09
ListenForClients is going to block whatever thread calls it while it listens for client connections. Most of the time, my Server class is created on the main thread. I don't usually want to block my main thread while waiting for connections, so I created another thread which can be blocked without affecting the rest of my application.
02/21/2008 - 07:08
When I close my win forms serverapplication (in debug state) it does not kill that thread. So what should I do? How I kill that clientThread and listenThread?
02/22/2008 - 10:55
For the clients, you'll want to call Close on their NetworkStreams. This will cause the read to unblock and throw an exception which will be caught by the exception handler (which breaks out of the loop, ending the thread).
On the TcpListener, you'll have to call Stop. I'm not sure exactly what this will do to the blocking AcceptTcpClient call. It will either unblock and return null, or it will throw an exception. Either way, you'll want to stick in some error handling. When the error is caught, simply break out of the listen loop.
02/25/2008 - 00:26
YES! it worked! yippee
thanks a lot!
02/26/2008 - 06:11
Sorry to be the newb.. but does someone have/know of an example of how to get data to and from the class to a form? :(
*sigh* I had an awesome idea for a program, but can't actually make a start on it cos I have to get this TCP stuff out of the way and I have no idea whats going on. :( I miss Winsock.. now that was simple. :)
02/26/2008 - 08:25
If by "the class" you mean the TCP server class, then it's not too hard. Inside the HandleClientComm thread, fire an event with the data that can be caught by your Form.
public event MessageReceivedHandler MessageReceived;
...
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
string message = encoder.GetString(message, 0, bytesRead);
if(this.MessageReceived != null)
this.MessageReceived(message);
Depending on how much information you need, you might want to also pass the TcpClient through your event as well. For a tutorial on custom event handlers, check out this post.
Now all you have to do is hook the event from your form.
server.MessageReceived += new MessageReceivedHandler(
Message_Received);
void Message_Received(string message)
{
//update the display using invoke
}
Since the events are fired on the server thread, you can't update the form directly - because you can't modify UI elements on threads that didn't create them. You'll have to use Invoke, which executes code on the UI element's thread. For some more information on invoking, I would recommend this article.
I hope this helps.
02/27/2008 - 17:01
woot, thanks Reddest. :)
02/27/2008 - 08:49
OK, I think I must be missing something here. I keep getting an error stating "You must call the start method before calling this method" on the TcpClient client = this.tcpListener.AcceptTcpClient() line.
I've definately started the server, any ideas what this could be?
Thanks a lot!
02/27/2008 - 11:37
That error is a result of not calling tcpListener.Start() before the call to AcceptTcpClient(). If you're saying you definitely called it, then I don't have any other ideas. I'd double to check to make sure you absolutely called tcpListener.Start().
02/28/2008 - 03:41
Hmm got a little further. The problem is to do with closing the server down. I can send data to it without error the first time, (creating the server object and sending the data from the same test case method) but next time I run the code I get a "Only one usage of each socket address (protocol/network address/port) is normally permitted" exception. I added a method to my server called Close that simply calls Abort on the listen thread and Stop on the TcpListener. If I call this after closing my request stream I get an IO exception while writing to the stream, above the point where I call the close method??
Really confused haha
02/28/2008 - 12:04
Calling Abort is never a good way to close your threads - and it's not actually a guarantee that the thread will terminate. Calling Stop() on your TCPListener should unblock your listen thread and throw an exception - which you should catch and return out of your function (which will end the thread).
Your first error is caused by calling Start() while another application is listening on that port. Typically, you can't have two TCP servers listening on the same port. Either your TcpListener was still running when you launched the application again, or you have another piece of software on your computer using that port.
03/17/2008 - 05:14
Excellent tutorial! Thanks a lot!
04/03/2008 - 04:09
when i got connected to the various clients in tcp listner(server)suppose initially if there are 1000 clients connected
but after some time it shows only 500 or 400 clients connected.actually clients are connected but server is not responding prooerly,but after stopping server it agains shows the actual no of the clients connected.(i thinks this problem is related to server port buffer size)plz help .....
04/08/2008 - 16:24
Hi,
i want to send data from a client to another client through server...
please help me
04/09/2008 - 10:40
How to do this depends a lot on the application you're trying to make, your protocol, and your server architecture. Here's an example scenario that might get you started.
When a new client is connected, you could assign them a unique id, or they could actually send you the id (a username or email address). This id would then be sent from another client in a request to forward the information.
This would mean your protocol would have to include the id of the client the other client wants to send data to. On the server, you'd simply read the message, get the id of the client to forward the message to, iterate through your clients to find the recipient, then send the data.
04/09/2008 - 21:21
Hi
Is it possible to send a class object from a TcpClient to TcpListener...
I want to send an object of a class or an array of string to the TcpListener
04/10/2008 - 09:38
It sounds like remoting is what you might want here, but it can also be done using TCPClient and TCPServer.
The send an object, you'll first need to serialize it to a byte array. Then, on the receiving end, deserialize the object back into the desired object. Here's a tutorial I found on the web explaining how to do this: Object Serialization and Deserialization in C#.
04/18/2008 - 05:57
Thanks alot Reddest...
i have one more question...
This TCPServer should run as a standalone application..or It can be programmed for a web service...
because I just want to run TCPServer as web servce in the server...
Please Help Me
05/03/2008 - 06:24
I have an application which is essentially a TCP/IP Server to which up to 16 clients can connect at any one time each on it's own unique port, i.e. 4001 - 4016.
The connections establish ok but after a period of time the connections seem to disconnect and I'm not sure why. when you run NETSTAT from the DOS Prompt it shows the connections in a CLOSE_WAIT state.
The clients then have to reconnect... and so the loop goes on...
Whe I try to write back to the client and it is disconnected I get an error code of 10053 which means that the software in the host machine has disconnected or something along those lines.
Has anyone else had experience of this? Could it be a timeout? How can I ensure that once my server accepts a client connection that it helps to maintain the established connection?
Any and all help appreciated.
Nigel.
06/02/2008 - 13:05
Thanks for the nice tutorial, just found it today.
Is there a way to start the server in its our thread at start? The reason i ask is because the user on my UI needs to click a button to start listening, but by doing so, it blocks my main UI.
Thanks!
06/02/2008 - 13:25
The server in this tutorial is created in its own thread. The constructor of the Server class creates the thread and begins the listening process. All you'd have to do is not call this.listenThread.Start() until the user clicks the button.
06/03/2008 - 13:07
Ahh, i see. I used a background worker to call the listen call and it also worked, will try the other.
One more thing, i am trying to pass a connected / disconnected status to the mainform as wel as the number for files received, any easy way to do that? So far im using you event example to send the message back but what are the procedures if i want to send more data back to my MainForm?
-Thanks!
06/09/2008 - 07:17
Hi. i am trying to get the client to read what the server sends but i am new to this. Can you tell me what i am doing wrong?
http://tagnard.net/2008/06/09/c-serverclient/
06/13/2008 - 04:46
Thanks for the nice tutorial. I tried it (ported to C++) and it works fine. Still, when exiting the main application I can't find a way to stop a clientThread when there is an active connection. I mean I can use tcpListener.Stop(), what causes a SocketException that unblocks AcceptTcpClient()in the ListenForClients thread, then I use break to exit the loop and this thread.
But if a client is actually connected, corresponding HandleClientComm thread remains stuck waiting for something to be read. So far, I haven't found any clean way to gracefully close the socket and to exit this thread.
I don't see how to close the NetworkStreams (as proposed in an earlier comment.) from the outside of the client thread. And from the inside, well the read is blocking, so...
Any idea?... Thanks, Eric
06/13/2008 - 07:17
I usually create an object for clients. The thread would be located inside the client object. The server would just keep a list of clients and whenever you stop the server, you'd loop through each client and call a stop function on them, which calls Close on their NetworkStreams.
You can modify the above code to do something similar by keeping a List of just the NetworkStreams. Whenever a new client is connected, add the NetworkStream from HandleClientComm. Whenever a client is disconnected, remove the NetworkStream from the list.
06/23/2008 - 05:00
thanks for the suggestion, it made it.
06/14/2008 - 18:48
Hi, have a strange problem... the tcp server connects fine with clients on the local network but 'kind of' connect with client comming from the Internet... it always wait about 16 - 20 seconds to connect, but then the remote client seems not to realize this... (also tcp port monitors show the incomming connection connecting almost immediately, but somehow not telling the server) please help...
06/17/2008 - 21:10
Hi, i have an error message
"A blocking operation was interrupted by a call to WSACancelBlockingCall" when set tcplistner.stop(), how to solve it ?
thank you
06/23/2008 - 05:00
this is normal behavior when interrupting a blocking socket (i.e. waiting for clients). WSACancelBlockingCall is called and a SocketException is thrown (see my post above). Just catch this exception and use it to exit the thread ('break' in the infinite while loop).
06/19/2008 - 05:35
Hi!
If it's possible, send me an initial code of this program. Please!
06/27/2008 - 08:10
Nice.. Easy to use and build on..
07/02/2008 - 18:07
Hi,
Since i m very beginner in C# coding for TCP/IP server.. I can get the concept and working of the code through ur explanation and questions but i cant do it practically./. Can u please explain that with a visual mode or the screen shots of wat to do?
Please help me bro..
I m in need of it..
I will b very grateful for the help ...
07/02/2008 - 18:09
ya its me again Saga..
Can u please mail me the one wich i asked in the previous thread...
My mail id: jeevan_saga@yahoo.co.in
07/04/2008 - 08:01
This is a great article; who explains clearly is really someone who really knows! I didn't give it a try yet but from the beginning it points to the TCPListener application blocking issue. I'll bring it into a chat-type application (client-server however) between two programs running on the same machine or remotely (first both on 'localhost'). I understand that threading the server separates it from the main program thread and avoid blocking all while in the listen loop. After acknowledging all that, just a stupid question (sorry I'm new to programming...): would it be possible that I make ListenForClients a method (rather than a class) of my main thread (since I want to quickly send and read messages from/into the main thread through your TCP server)? Many thanks!
07/08/2008 - 13:17
Hey, not much to add. Just wanted to say great thread. EXCATLY what i've been looking for.
THANKS!!!
07/09/2008 - 08:57
Thanks
07/14/2008 - 15:38
Hi,
i am in a big trouble to fix this problem....
can any one suggest me a control,
which can display animated gif images and text....
this is for a chat application....
07/16/2008 - 13:46
Ok... so I got the client-server part done quite easily...
What I want to do now is to have two way async communication using this only connection. Is that possible or do I have to have two connections, one for reading and one for writing, on different ports? Any other way you can suggest?
07/16/2008 - 18:39
I have a very weird problem here. When I copy and paste the client into visual C# studio 2008, it doest recognise the .Connect method of a TcpClient.
Please help me! Thanks.
07/18/2008 - 11:28
Hi,
I have develeped webcam view in my chat.In that only one client can view webcam at time.I want to do view more than one client at time(web cam sharing).I am using TcpListner and TcpClient.Can Anyone Help Plz.Urgent.Thanks In Advance.
07/23/2008 - 04:55
thank you
07/29/2008 - 18:41
Gonna try yours. Too soon to tell, but no crashes so far (like mine).
One issue I have always had with the GPS via GPRS devices we track: they will un-gracefully disconnect when they switch cell towers, then reconnect. So eventually, there's lots of dead connections that are not recylced. I tried making a collection and saving each client object as it's created. The idea was to purge the clients, but I am not sure how:
clientArrayList.Add(client);
...so now I have the client objects in my collection. But I get errors when I try to delete them like this:
{
c.Client.Close();
}
So I guess I am still looking for a way to recycle these old connections. Suggestions appreciated.
08/04/2008 - 14:04
I would like to say thanks. The main article is detailed and straight forward but the additional information in the comments has also been very helpful.
08/23/2008 - 00:24
very simple as well useful beginner like me,,,,,,,.
09/02/2008 - 07:32
Anybody,
have you had any issues with a (C#) socket exiting into a CLOSE_WAIT therefore not allowing to use the same address/port.? I am closing the connection at both ends and still get the CLOSE_WAIT (not all the time).
I used extensively C/C++ berkley socket and I never got the problem.
Anybody?
10/17/2009 - 15:15
a CLOSE_WAIT usually indicates a problem in the app (server), probably from not closing the socket. You need to catch when the client closes (or times out/drops off/whatever) and close on the server side. You should see TIME_WAIT (ok), but CLOSE_WAIT is usually not good sign.
09/27/2008 - 04:48
Good article, hope you will keep up ,creating more of it, in the same simplify style, someday. :)
Thx!
10/25/2008 - 16:07
Good article!!!
Procurei por um assim a temposs..
muito bom msm ... parabéns!!
11/10/2008 - 16:27
Excellent tutorial and very useful from both clarification and simplification perspectives.
Just one thing: shouldn't clientStream.Close() be called prior to tcpClient.Close() in HandleClientComm? Otherwise, won't the network stream remain open (unless if that was by design/intention, although I don't see why, and how, one could recover the same stream for future use after closing the TcpClient)?
Thanks again and great work!
11/27/2008 - 03:02
Awesome tutorial. Thanks Reddest.
12/10/2008 - 15:58
I am new in this tcp programing and just have question:
I have created the TCPServer.dll and tcpClient.exe, how to test thme?
12/10/2008 - 15:58
Sorry give the confuse, and question is simple: How to start TCPServer?
12/10/2008 - 17:09
In my example code the server is started automatically upon construction.
12/24/2008 - 10:28
Hi there Reddest,
I am developing a MUD (multi user domain) in C# and i wanted to ask a question:
What i need is an application just like this, but i want the ability to have events driven by commands texted into the MUD, i’m sure you may be familiar with old school MUDs, if not its a text based D + D type adventure game, supporting multiple users that can interact. There will be chatting of course, but mainly each user will have commands and need series of data stored (in class objects i’m certain)
ANYWAY, What i need is to know if this threading business will affect each user? Like if i’m player Johnny and johnny does this or that in the game, how will other players in the room be made aware? IS this the wrong type of server for my needs? Thanks!
12/26/2008 - 09:06
Exactly what I was looking for ^^
12/28/2008 - 12:42
Forgive me if this has already been answered, but I didn’t see it.
Is there a way to send the chat messages the server receives to all the connected clients?
12/30/2008 - 05:57
Great code…simple and stable;
If you want to test your tcp server with simulated clients, you can use ‘telnet’ to achieve this.
Open a command prompt window in XP or Vista.
Type the following command:
telnet host port
where host=local computer name, ip address(127.0.0.1 will always be your own computer) or domain name that identifies the computer on the internet.
port = port number the TCP server is supposed to listen to
If you have a successfull connection then a black screen with a blinking cursor should appear.
If you open more command windows and issue the same command you will simulate multiple clients connected to the server.
Closing that command windows should disconnect that client.
Cheers,
12/30/2008 - 06:07
Forgot to mention:
sending information to your server using telnet and beeing able to parse it is not possible unless your TCP server uses VT100 Application layer protocol, which an end programmer has to manually implement it.Though i strongly discourage to do that.
You can use telnet to test server shutdown, while clients are connected and beeing able to easily troubleshoot exceptions, manage server resources when clients connect/disconnect and even troubleshoot timeout disconnect methods if you clients are connected, but donn’t send anything over a period of time.This is very a server memory friendly approach since a real server needs to handle thousands of simultaneous connections at a given time.
12/30/2008 - 23:29
I can get the server to send information to the client, but its a blocking call. How do you make the client listen for incoming data from the server and keep the GUI alive at the same time?
Thanks in advance.
01/19/2009 - 17:19
Your tutorial was a great way to get starting on networking in C#. You are very good at explaining this hows og whys :)
Thanks a bunch!
02/04/2009 - 04:47
Man I registed JUST to tell you how amazing this tutorial is and how good you are at explaining stuff. I browsed I dont know how many tutorial about this without understand shit, but with you it was so simple, easy and amazing...
/bow
You are my new god! :)
02/25/2009 - 07:03
Hi thanks for good tutorials.
I have a serious problem. I want to develope an "server" that can recieve streaming data from sensors (the number of could be variated), Then the data should be pushed after it has been "modified" a bit, into the database (SQL Server).
I dont know where to start, im aware that it may will need some kind of a server and it looks like that i also need threads and async communication.
But how can i recieve stream data directly with TCP?
03/04/2009 - 01:38
hi thanks for gud concepts..
but iam confused at Async ..
03/05/2009 - 15:17
Worked the first time I used it. Many thanks, you saved my bacon...
04/02/2009 - 08:27
greate explanation
04/02/2009 - 08:29
but i think we will find "out of memory Exception"
when alot of clients conected
as we creare aseparate thread for Each client
so these no of threads will lead to that exception
05/05/2009 - 08:22
Hi thanks, for the great tutorial,
BUT the NetworkStream.Read() command seems to work only the first time. I copied your code exactly (!), compiled and started the server. When I connect via telnet 127.0.0.1 3000 (or any other client) I can just send the first time. The second time NetworkStream.Read throws following Exeption.Message: "The argument is out of range of valid values! Parameter: size ...
Do you have any suggestions?
Cheers, littleman
05/05/2009 - 08:39
solved .... :)
05/05/2009 - 08:58
What was the issue?
05/09/2009 - 01:38
Hi, Every one i have a card reader secrutiy device of pegasus brand, which is connected on port 4001 , i want to read and wirite data on this device any one help me please, while i am using Visual studio 2008 C# code
05/12/2009 - 05:02
Hi Reddest, great tutorial and code!
I was wondering what a realistic number of concurrently connected clients (=~ threads in this case) would be in this implementation, on a standard modern PC using winXP SP3 and VS 2008 / .NET 3.5 SP1
I realize this may depend on many factors, but a rough estimate would be great - dozens of clients? hundreds? thousands?
Much appreciated,
Ohad
06/10/2009 - 09:38
Great article. Well written and easy to understand. I wish all articles were like this one !
06/15/2009 - 16:32
Great article. One question though. Since the AcceptConection is blocking on the thread, How can I gracefully end everything when the Server, in my case a form, closes?
06/15/2009 - 16:38
When TCPListener.Stop() is called, it will unblock with an exception. Simply catch the exception and break out of the loop.
06/16/2009 - 11:27
that is what I was doing, just wanted to see if there was some other way that did not raise an exception.
06/16/2009 - 11:36
You can probably get around it using BeginAcceptTcpClient and EndAcceptTcpClient.
07/03/2009 - 14:02
Hi,
I've implemented your server solution and it works fine except that threads seem to be accumulating and not being released as the clients close their connection. Everytime a connection is caught by the TcpListener the size of the application in memory grows by a few kB but upon the final tcpClient.Close() in the HandleClientComm the ressources don't seem to released. So my application is constantly inflating... It was my understanding that once the connection was closed the thread would simply vanish?
thanks!
07/05/2009 - 17:05
Hi again its tohox,
So I did my homework thoroughly debugging my app, reading many things about threading and .Net memory management and it appears that this memory inflation is somewhat normal given the way managed code works and how the garbage collector handles ressources.
When hitting the server with many requests per second the memory usage quickly grows to a few MBs more than when the server was first started and it then tends to stabilize. After that it will occasionnaly grow or shrink but stays roughly the same. Forcing the garbage collector to do its job will momentarily free up a few kilobytes but memory usage will eventually crawl back up...
So, false alarm and many thanks for a great tutorial!
08/03/2009 - 19:47
Thank you for the article. This is the first piece i've seen on tcp communication in c# .net. I have a question for you though. Is it common practice to use a blocking loop to wait for client connections? It seems a bit like a duct tape solution to me. Are there no .Listen() methods or anything of that nature? Would a .Listen() method simply wrap a blocking loop? Just seems... i don't know... inelegant?
Thank you again though. Great article. :)
08/04/2009 - 08:52
I like to use the blocking call myself, but there are asynchronous methods that won't require it. Check out BeginAcceptTcpClient and EndAcceptTcpClient.
08/13/2009 - 07:44
thanks for this good article so much really i have searched a lot but this was the best
i have a silly question as i am new to network programing
what happen if the accept client has no object to return??
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
11/23/2009 - 06:33
run your program and place breakpoints at the accept client line and one at the line just after that, you will see that the accept client will not move to the next code line untill a client is connected so the object will not be nothing
08/29/2009 - 02:51
Great article, but how can I use this one when I want to connect to a remote computer on Internet with a router(a local ip adress)
08/30/2009 - 18:53
In this example, the TCP server is listening on port 3000. The router would have to be configured to forward that port to your desired computer.
09/06/2009 - 23:43
What a clean and great sample you've posted. I was just wondering one thing. Would you be so kind to perhaps post the following code updates if its not to complicated:
+ Everytime the server accepts a client, this client is added to a list.
+ Everytime a message is sent to the server, a true or false flag is sent as well telling the server to broadcast the message back to the client who sent it or to all clients on the list of connected clients.
09/08/2009 - 21:26
Great article, thanks for posting this. I have a problem though...
It seems that the server can only be connected to using a client on the same computer as the server or on the same network (intranet).
How do I open the server up to connections from the open internet?
Thanks in advance to anyone who can help me with this issue!
09/12/2009 - 00:52
Here is my code:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace SimpleConsoleServer
{
class Program
{
// Global methods
private static TcpListener tcpListener;
private static Thread listenThread;
private string endl = "\r\n";
/// <summary>
/// Main server method
/// </summary>
static void Main(string[] args)
{
tcpListener = new TcpListener(IPAddress.Any, 80);
listenThread = new Thread(new ThreadStart(ListenForClients));
listenThread.Start();
}
/// <summary>
/// Listens for client connections
/// </summary>
private static void ListenForClients()
{
tcpListener.Start();
while (true)
{
try
{
// Blocks until a client has connected to the server
TcpClient client = tcpListener.AcceptTcpClient();
// Create a thread to handle communication
// with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
catch (Exception)
{
}
}
}
/// <summary>
/// Handles client connections
/// </summary>
/// <param name="client"></param>
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
// Blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch (Exception)
{
// A socket error has occured
break;
}
if (bytesRead == 0)
{
// The client has disconnected from the server
break;
}
// Message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
// Output message
Console.WriteLine("To: " + tcpClient.Client.LocalEndPoint);
Console.WriteLine("From: " + tcpClient.Client.RemoteEndPoint);
Console.WriteLine(encoder.GetString(message, 0, bytesRead));
} while (clientStream.DataAvailable);
// Release connections
clientStream.Close();
tcpClient.Close();
}
}
}
09/13/2009 - 18:40
Follow-up:
I resolved the issue. Apparently the corporate domain my computer was joined to had settings which blocked all ports for incoming requests not on the domain.
10/21/2009 - 06:26
Hi I've been trying to piece together some code from this tutorial for my application and have come across a few problems.
Can anyone help me out with seeing why I can't send more than one message in either direction with the code I have, and why this would be the case. I get the feeling I've done something seriously wrong!
Thanks for any help.
Server Side
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace TcpTrainServer
{
public partial class Form1 : Form
{
private static TcpListener tcpListener;
private static Thread listenThread;
static NetworkStream clientStream;
static string textFromClient = "";
//private string endl = "\r\n";
public delegate void MessageReceivedHandler(string message);
public event MessageReceivedHandler MessageReceived;
public Form1()
{
InitializeComponent();
initiateListen();
}
private void initiateListen()
{
tcpListener = new TcpListener(IPAddress.Any, 8000);
listenThread = new Thread(new ThreadStart(ListenForClients));
listenThread.Start();
}
/// <summary>
/// Listens for client connections
/// </summary>
private static void ListenForClients()
{
tcpListener.Start();
while (true)
{
try
{
// Blocks until a client has connected to the server
TcpClient client = tcpListener.AcceptTcpClient();
// Create a thread to handle communication
// with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
catch (Exception)
{
}
}
}
private void buttonStartListening_Click(object sender, EventArgs e)
{
initiateListen();
}
/// <summary>
/// Handles client connections
/// </summary>
/// <param name="client"></param>
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
//NetworkStream clientStream = tcpClient.GetStream();
clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
// Blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch (Exception)
{
// A socket error has occured
break;
}
if (bytesRead == 0)
{
// The client has disconnected from the server
break;
}
// Message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
// Output message
textFromClient = tcpClient.Client.LocalEndPoint + " " + tcpClient.Client.RemoteEndPoint + encoder.GetString(message, 0, bytesRead);
//Console.WriteLine("To: " + tcpClient.Client.LocalEndPoint);
//Console.WriteLine("From: " + tcpClient.Client.RemoteEndPoint);
//Console.WriteLine(encoder.GetString(message, 0, bytesRead));
} while (clientStream.DataAvailable);
// Release connections
// clientStream.Close();
//tcpClient.Close();
}
private void timer1_Tick(object sender, EventArgs e)
{
textBoxMessage.Text = textFromClient;
}
private void buttonClear_Click(object sender, EventArgs e)
{
textFromClient = "";
textBoxMessage.Clear();
}
private void buttonSendToClient_Click(object sender, EventArgs e)
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Server!");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
}
Client Side (User App)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace UserApp
{
public partial class Form1 : Form
{
static TcpClient client;
IPEndPoint serverEndPoint;
NetworkStream clientStream;
static String textFromServer;
public Form1()
{
InitializeComponent();
iniTCP();
}
public void iniTCP()
{
client = new TcpClient();
serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000);
}
public void connectTCP()
{
client.Connect(serverEndPoint);
clientStream = client.GetStream();
// Create a thread to handle communication
// with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
public void sendMsg()
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Testing TCP/IP connection");
clientStream = client.GetStream();
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
//clientStream.Close();
}
private void button1_Click(object sender, EventArgs e)
{
connectTCP();
}
private void buttonSendMessage_Click(object sender, EventArgs e)
{
sendMsg();
}
/// <summary>
/// Handles client connections
/// </summary>
/// <param name="client"></param>
private static void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
// Blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch (Exception)
{
// A socket error has occured
break;
}
if (bytesRead == 0)
{
// The client has disconnected from the server
break;
}
// Message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
// Output message
//textFromServer = tcpClient.Client.LocalEndPoint + " " + tcpClient.Client.RemoteEndPoint + encoder.GetString(message, 0, bytesRead);
textFromServer = tcpClient.Client.LocalEndPoint + " " + tcpClient.Client.RemoteEndPoint + encoder.GetString(message, 0, bytesRead);
} while (clientStream.DataAvailable);
}
private void buttonClose_Click(object sender, EventArgs e)
{
// Release connections
clientStream.Close();
//tcpClient.Close();
}
}
}
10/21/2009 - 08:14
My only guess is that clientStream.DataAvailable is returning false. DataAvailable only returns true if data is available to be read. Since you're reading all of the data from the stream in the loop, it will most likely revert to false by the time the loop ends.
10/21/2009 - 17:17
ok so with that aside, am I right in my understanding that once a "clienstream" has been established between server-client that they can send/receieve using this without any issues with blocking sockets or anything like that?
In your example you have this code to send from server-client
NetworkStream clientStream = tcpClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Client!");
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.Flush();
Was I correct in adding a handlecomm method at the client end because how else would the application know how to handle the receival of data?
Im confused in regards to the part where say I go to send a message from client-server, how is it that only the server "handlecomm" and not the client "handlecomm" won't see data in the stream to be read?
Thanks
10/22/2009 - 17:56
disregard my last message, I got it working, you were right about the DataAvailable returning false. I've just placed an infinte true loop around the other loop, not sure if thats the best way to get around it but its working!!
Thanks heaps
10/23/2009 - 07:33
You could just replace the inner loop with a while(true) loop. On error conditions you call break, which will correctly exit the loop. If you surround the inner loop with another one, you might have problems getting that thread (and your application) to exit.
10/27/2009 - 10:33
I have modified a bit client and server, so that server replies to client and they communicate until client types "exit".
CLIENT
while (true)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("SEND: ");
buffer = encoder.GetBytes(Console.ReadLine());
if (encoder.GetString(buffer) == "exit")
{
break;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("SENDING: " + encoder.GetString(buffer));
clientStream.Write(buffer, 0, buffer.Length);
Console.ForegroundColor = ConsoleColor.Red;
clientStream.Read(buffer, 0, buffer.Length);
Console.WriteLine("REPLY: " + encoder.GetString(buffer));
}
SERVER:
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
Console.WriteLine("RECEIVED: " + encoder.GetString(message, 0, bytesRead));
//REPLY
/*sMessage = encoder.GetString(message, 0, bytesRead);
sMessage = sMessage.ToUpper();
Console.WriteLine("REPLY: " + sMessage);
message = encoder.GetBytes(sMessage);
Console.WriteLine("REPLY: " + encoder.GetString(message, 0, bytesRead));
clientStream.Write(message, 0, bytesRead);*/
/*message = encoder.GetBytes(encoder.GetString(message,0,bytesRead).ToUpper());
Console.WriteLine("REPLY: " + encoder.GetString(message, 0, bytesRead));
clientStream.Write(message, 0, bytesRead);*/
byte[] buffer = encoder.GetBytes(encoder.GetString(message, 0, bytesRead).ToUpper());
clientStream.Write(buffer, 0, buffer.Length);
Console.WriteLine("REPLY: " + encoder.GetString(buffer, 0, buffer.Length));
clientStream.Flush();
}
Can you tell me why only the last "method" in server works ? If I try to do the same thing with two previous "methods", after receiving first message from client and sending it back, server shows that client has disconnected.
On the other hand those two "methods" work fine if I don't try to do anything with buffer (just send it back).
10/28/2009 - 08:36
Why can't I use the same buffer I received message to ?
11/18/2009 - 11:40
I need help urgently.
An application written in C++ writes messages in the form of (char*) struct continuously.
I need to create a windows server ( written in c#) that would receive that message from that socket and parse that and send the information back again in the same socket.
Please help me
1. how the c++ message will be read by c# codes?
2. How the threading model would be for the c# application?
3.How it will write data into socket that would be readable by c++ application?
PLeeeeeASE HELP.
01/06/2010 - 18:22
C# will have no problem receiving CPP char*s (they point to char[]) and CPP will have no problem receiving C# char[]s, it depends on your methods for retrieving data.
Perhaps something more "beginnerish" would be beneficial before tackling threading and sockets..
12/09/2009 - 18:26
excellent tutorial
12/09/2009 - 18:27
Console.WriteLine("Thank you for the tutorial.");12/10/2009 - 22:05
is there any way to test the connectivity(telnet or ping) using C# .net if we enter the source(usually not the machine logged in) ip port and destination ip port in a simple form?
Thanks in Advance.
12/21/2009 - 10:01
Hello. Need your help!
In the article you've said that you usually save collection of TCPClient. Is there any way to detect the client is discinnecting?
Thanks for any advices!
12/21/2009 - 10:09
Yes, clientStream.Read(message, 0, 4096), will throw an exception (probably IOException), which indicates the underlying socket has been closed.
12/22/2009 - 02:58
Thanks a lot! I'll try this.
12/30/2009 - 03:01
Hello,
how do you stop the server? I mean, your Read call has Infinite timeout so the call will block forever.
Then, how do you can stop the server if you need to?
01/26/2010 - 13:36
This stuff looks interesting although I can't seem to get any of the examples to compile in Visual Studio 2005.
Can anyone post a complete compileable example of the client and server app where data communicated between the client and server is displayed in a form control?
02/07/2010 - 23:31
Hello everyone,
I am new in Socket programming, I want to send file in chunks from server to client side. As server send packet(packetID + SizeofPacket + Data) to client side, Client save the data in buffer and send the response(packetID) back to server. then server looks the packetID and send the datachunk related to packetid.
Can I achieve this by using TCP sockets. Can someone explain me how. Thanks
02/09/2010 - 14:52
Curiosity: the example starts a thread to handle the communications and provide the "intelligence" (HandleClientComm).
What about using
AcceptTcpClient(which blocks until a connection is available) - acquiring the entire message - and then spawning a thread to provide the process? Yes, the acquisition of the message is then in-line, but, if I read my TCP specs correctly, it will always be in-line because of the buffers.For example:
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
for (lr.Start(); MyListenerIsNotShutDown);)
{
TcpClient cl /*Client*/ = lr.AcceptTcpClient();
byte[] bf /*Buffer*/ = new byte[8192];
string mg /*Message*/ = string.Empty;
NetworkStream sm /*Stream*/ = cl.GetStream();
for (int ct = sm.Read(bf, 0, bf.Length - 1); 0 < ct; ct = sm.Read(bf, 0, bf.Length - 1))
mg += Encoding.ASCII.GetString(bf, 0, ct);
mg = mg.Trim();
try
{ // Start a new thread to process this message.
Thread thd /*Thread*/ = new Thread(new ParameterizedThreadStart(MyMessageProcessor));
thd.Start(mg);
}
#pragma warning disable 168
catch (OutOfMemoryException ex /*Exception*/)
{ // There is not enough memory to start the thread: do it in-line, thereby, throttling responses.
MyMessageProcessor(mg);
}
#pragma warning restore 168
...
public static void MyMessageProcessor(object prmMsg)...Just to add to the confusion, the send is therefore stateless:
cl.Connect(new IPEndPoint(IPAddress.Parse(prmAdr), prmPrt));
ASCIIEncoding ec /*Text Encoder*/= new ASCIIEncoding();
byte[] bf /*Buffer*/ = ec.GetBytes(prmMsg);
NetworkStream sm /*Stream*/ = cl.GetStream();
sm.Write(bf, 0, bf.Length);
sm.Flush();
02/22/2010 - 16:19
Never mind... Don't do it (spawn the thread AFTER acquiring the text)... The newer Windows TCP stacks do indeed provide for multiple, concurrent connections' queues being drained.
02/17/2010 - 10:21
Hello, is it possible that 2 clients connected to same server can communicate each other using c# multithreading programming?? Thanks... I need help
02/22/2010 - 16:31
The server merely receives and replies to clients; client to client communications are not possible ... strictly speaking.
I suppose you could write your server's message handler to recognize some kind of forwarding command prefix in the message (eg: "To 12.34.56.78:50000"). The sending client would have to put that it its message. However, that brings up the question, "If the client knows the IP address and port of the other client, why is it not sending the message directly?"
02/23/2010 - 13:08
Hi, I am writing Bluetooth simulation program in c#. I am writing two clients as Master and Slave device. and one server application which act as a channel between Master and Slav device. so, Master communicate with Slave through Channel. Later I will add interference at channel application and see the effects on Master and Slave, as these Master sending a big file in chunks to Slave.
Please I need your's suggestions, how I achieve this???
Thanks
Khan
03/01/2010 - 21:20
hii, how to receive and send data to linux client from .NET using format
struct tcpdata {
unsigned long code;
unsigned char msg[256];
}
thanks,
03/11/2010 - 09:32
I got most of this working ... in a "harsh" environment (slow processors at both ends, zilch memory). Here is what I learned:
1- recv returns zero when its current crop of buffers for the connection are empty. THAT DOES NOT MEAN THE MESSAGE IS FULLY ACQUIRED! Maybe everybody else got this; I didn't and had to add an endian-independent, length field at the beginning of each message.
1b- mrRumble - "On the nose!" (length field at the beginning of each message) ... except that there are a number of machines of different "endianness" that do not store the bytes of an unsigned long in the expected order (assuming you want to talk to not just C# nodes). You must replace that unsigned long (or long) with four, distinct byte values, where you know that the first one is the high-order, and so on (or whatever order you want, as long as it's consistent).
2- When the client (sending) side is C# and the server (receiving) side is C/C++, when the C# closesocket executes, unread data at the server (C/C++) side (or, maybe, still in flight) is destroyed ... sometimes ... often enough to be catastrophic. Strangely enough, this does not seem to happen in reverse (C/C++ client sending to a C# server). I found two WWW reports of similar behavior - "fire and forget" is not a good philosophy, here. The answer is to require some kind of acknowledgment for every transmission (for example, an empty message) before the sender executes closesocket.
3- The idea of the loop around the server's loop is a real frustration-preventer: having the code able to say, "This failure is too nasty for me to handle in the inner loop; I'll reset and restart everything!" definitely makes unit testing more pleasant. I suggest a Sleep of a good second or so at the end of the outer loop:
if (this is not a shutdown) Sleep(1000);to give the system some cycles to tidy whatever messes it needs to clean up and, maybe, restore resources that will allow the next, major cycle of your server to execute successfully.
4- Consider UDP instead of TCP. If you can do what you need to do in UDP, use it instead of TCP. Remember, UDP blasts your packets all over the place: they WILL arrive out of order. You'll need, instead of just a length field, a (packetN)/(ofMpackets) field in each transmission. ...but UDP is much faster, simpler, and, oddly enough, can end up being more robust than TCP. Hard to swallow, I know, but that has been our experience: UDP gets more data through bad pipes than TCP does.
...hope this saves somebody some grief...
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.