views:

629

answers:

4

Hi Everyone,

I am currently creating a Windows Service that will create TCP connections to multiple machines (same socket on all machines) and then listen for 'events' from those machines. I am attempting to write the code to create a connection and then spawn a thread that listens to the connection waiting for packets from the machine, then decode the packets that come through, and call a function depending on the payload of the packet.

The problem is I'm not entirely sure how to do that in C#. Does anyone have any helpful suggestions or links that might help me do this?

Thanks in advance for any help!

A: 

Have a single thread that runs the accept() to pick up new connections. For each new connection you get, spawn a worker thread using the thread pool.

Andrew
+1  A: 

Depending on how many concurrent clients you plan on supporting, a thread-per-connection architecture will probably break down very quickly. Reason being, each thread requires significant resources. By default each .NET thread gets 1MB of stack space so that's 1MB per connection plus any overhead.

Instead when supporting multiple connected clients typically you will use the asynchronous methods (see here also) which are very efficient because Windows will use "completion ports" which basically free up the thread to do other things while waiting on some event to complete.

For this you would look at methods such as BeginAccept, BeginReceive, BeginSend, etc.

A simpler approach which also avoids making blocking calls and avoids multiple threads is to use the Socket.Select method in a loop. This allows a single thread to service multiple sockets. The thread can only physically read or write to a single socket at a time but the idea is that you are checking the state of multiple sockets which may or may not contain data to read.

In any case, the thread-per-connection approach is much simpler to get your head around at first, but it does have significant scalability problems. I would suggest doing that first with the synchronous methods like Accept, Receive, Send, etc. Then later on refactor your code to use the asynchronous methods so that you don't exhaust the server's memory.

Josh Einstein
A: 

I don't know if it's possible in your situation but have you thought about using a WCF service that gets called by the multiple machines ? You can host this in a custom windows service or IIS. It will consume very little resource while waiting for events and it's much simpler to code than all that low level scary socket stuff. It's automatically async. You get nice messages to your service rather than a packet you need to deserialize and/or parse. You can use any number of protocols such as REST or binary.

You will of course need to create the process on the other end that sends the messages.

Just a thought...

Cheers

Jonesie
+1  A: 

You can have asynchronous receive for every socket connection and decode the data coming from other machines to perform your tasks (You can find some useful information about asynchronous methods here: http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx).

To create a connection, you can do:

Socket sock = Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(new IPEndPoint(address, port));

Same way you can create multiple connections and keep there references in a List of Dictionary (whichever you prefer).

For receiving data asynchronously on a socket, you can do:

sock.BeginReceive(buffer, 0, buffer.len, SocketFlags.None, new AsyncCallback(OnDataReceived), null);

The method OnDataReceived will be called when receive operation completes.

In OnDataReceived method you have to do:

void OnDataReceived(IAsyncResult result)
{
   int dataReceived = sock.EndReceive(result);
   //Make sure that dataReceived is equal to amount of data you wanted to receive. If it is
   //less then the data you wanted, you can do synchronous receive to read remaining data.

  //When all of the data is recieved, call BeginReceive again to receive more data


  //... Do your decoding and call the method ...//
}

I hope this helps you.

cornerback84