tags:

views:

678

answers:

4

We're creating a c# app that needs to communicate with one other system via TCP/IP sockets. We expect to receive about 1-2 incoming transactions per second, each message averaging around 10k in size (text and 1 image).

We'll then do some processing (could take anywhere from 100 milliseconds to 3 seconds, depending on a few variables), and then send a response back of around 1k.

In the examples I've looked at, some are multi-threaded. For this application, would it be better to make it single or multi-threaded? If multi-threaded is recommended, roughly what would the different threads do?

+3  A: 

If you're expecting multiple connections you'll need multiple threads. Each thread will be given streams for a particular client which it will need to handle separately.

I think the Silverlight policy server is a great first time example of a multithreaded server app. Though, it uses the Socket class instead of the TcpListener.

Spencer Ruport
Would you say that many connections on the same port from the same client constituted "multiple connections" or just one connection?
alchemical
It's still considered multiple connections.
Spencer Ruport
+5  A: 

(not specific to C#)

Having done it both ways (extreme performance was not the deciding factor), I much prefer the 1-thread-per-connection approach.

Listener Thread
The job of this thread is to listen on the socket for incoming connections, accept them, and spawn a new connection thread (giving it the connected socket).

Connection Threads
These threads (one per connection) handle all of the communication with the connected socket. They may also handle the processing of requests if it is synchronous (you will need to look into that for your specific app).

When the connection dies, this thread dies as well.

Management Threads
If cleanup, or periodic maintenance need performed, these can all run in their own threads.

Just keep in mind locking (obviously): How much data do connections need to share? Make sure all of your resources are correctly locked when accessing, and that you do not have any deadlocks or race conditions. That is more of a "general threading" topic however.

gahooa
Consider using Thread-pools instead of spawning a new thread per each request. Creation of new thread can be expensive and provides good opportunity for DOS attacks.
CsTamas
There will be a few shared resources: a database connection object, a logging object, etc. These are generally thread-safe singletons, but I could also look at giving each thread its own instance...
alchemical
If extreme performance was not your main consideration--what led you to prefer multiple threads?
alchemical
It's not extreme performance. It's functioning performance.
Spencer Ruport
@NagaMensch -- In this given case (Python), using threads was a lot simpler because each thread could be coded so that it believed that it was the only connection in the program. This also allowed the use of blocking sockets. We wrote the program with an event loop + non-blocking sockets, and then re-wrote it with threads + blocking sockets. Threads were preferable.
gahooa
+1  A: 

I would accept sockets and use async calls. Allows you to accept multiple connections and avoids creating a thread for every connection.

Basically create a socket with the listener

Socket socket = tcpListener.AcceptSocket();

and Socket.BeginReceive to start receiving data.

Marcom
A: 

I think it's important to define what is meant by the word 'connection.'

If the other system creates a new connection to your TcpListener each time a transaction is sent, then this would be considered multiple connections, and it would make sense to have a dedicated thread to process these incoming connection requests. If this is the case, ignore everything beyond this and use gahooa's suggestion solution.

On the other hand, if the other system simply establishes a connection and sends all transactions over that same connection, then there's really no point in processing the connection request in a separate thread (since there is only one connection). If this is the case, then I would suggest accepting the incoming request once and reading the socket asynchronously (as opposed to polling the socket for data). Each time you receive a complete transaction, throw it "over the wall" to a transaction processing thread. When the processing is complete and the "answer" is computed, throw it "over the wall" to a response thread that sends the result back to the other system. In this scenario, there are basically four threads:

  1. Main thread
  2. Read thread
  3. Processing thread
  4. Write thread

The Main thread creates the TcpListener and waits until the connection is established. At that point, it simply initiates the asynchronous read and waits until the program ends (ManualResetEvent.WaitOne()).

The Read thread is the asynchronous thread that services the reading from the NetworkStream.

The Processing thread receives transactions from the Read thread and does whatever processing is necessary.

The Write thread takes whatever responses are generated by the Processing thread and writes them to the NetworkStream.

According to this link, you do not have to synchronize the reading and writing from the same NetworkStream as long as the reading and writing are done in separate threads. You can use a generic List or Queue to move data between the threads. I'd create one for the Read-to-Processing data and one for the Processing-to-Write data. Just be sure to synchronize access to them using the SyncRoot property.

Matt Davis