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:
- Main thread
- Read thread
- Processing thread
- 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.