Basically what you're trying to do is a reactor. You can find open source library implementing this pattern. For instance:
http://www.cs.wustl.edu/~schmidt/ACE.html
http://pocoproject.org/
If you want yout handler to have the possibility to do more processing you could give them a reference to your TCPServer and a way to register a socket for the following events:
read, the socket is ready for read
write, the socket is ready for write
accept, the listening socket is ready to accept (read with select)
close, the socket is closed
timeout, the time given to wait for the next event expired (select allow to specify a timeout)
So that the handler can implement all kinds of protocols half-duplex or full-duplex:
In your example there is no way for a handler to answer the received message. This is the role of the write event to let a handler knows when it can send on the socket.
The same is true for the read event. It should not be in your main loop but in the socket read handler.
You may also want to add the possibility to register a handler for an event with a timeout so that you can implement timers and drop idle connections.
This leads to some problems:
Your handler will have to implement a state-machine to react to the network events and update the events it wants to receive.
You handler may want to create and connect new sockets (think about a Web proxy server, an IRC client with DCC, an FTP server, and so on...). For this to work it must have the possibility to create a socket and to register it in your main loop. This means the handler may now receive callbacks for one of the two sockets and there should be a parameter telling the callback which socket it is. Or you will have to implement a handler for each socket and they will comunnicate with a queue of messages. The queue is needed because the readiness of one socket is independent of the readiness of the other. And you may read something on one and not being ready to send it on the other.
You will have to manage the timeouts specified by each handlers which may be different. You may end up with a priority queue for timeouts
As you see this is no simple problem. You may want to reduce the genericity of your framework to simplify its design. (for instance handling only half-duplex protocols like simple HTTP)
The solution to your problem is to use lock-free algorithms allowing for system wide progress of at least one task. You need to use inline assembler that is CPU dependent to make sure that you atomic CAS (compare-and-swap). Wikipedia has an article as well as patterns described the the book by Douglas Schmidt called "Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects". It is not immediately clear to me how you will do that under the dotnet framework.
Other way of solving your problem is using the publish-subscriber pattern or possible thread pools.
Using asynchronous communication is totally possible in single thread!
There is a common design pattern in network software development called the reactor pattern (look at this book). Some well known network library provides an implementation of this pattern (look at ACE).
Briefly, the reactor is an object, you register all your sockets inside, and you wait for something. If something happened (new data arrived, connection close...) the reactor will notify you. And of course, you can use only one socket to send and received data asynchronously.
You will hear discording opinions about design patterns, in the programming community at large.
In my opinion, it is sure that there are abstractions that patterns encapsulate that are really useful (factory, singleton, delegate, etc.). I use patterns a lot, but I myself am sometime puzzled by the apparent lack of depth or level of insight that you get by reading a pattern description. This is also in tune with the proliferation of design patterns that specialize for any kind of things.
When the design hey are useful, they are a very good means of communication and certainly they guide you through the process of designing or defining the architecture of your app. They are useful both for small project and for large ones, and they can be applied at different granularity levels.
Patters are a generic concept and all programming languages support them. Anyway, if you work in C++, a book focusing on it is best, because you will get the pattern adapted to the characteristics of the language.
In my opinion, the really fundamental book about design patterns are:
There are numerous patterns that could solve the problem, but the key point in making the decision is understanding the pattern's consequences. The ACE website has some papers for some concurrency patterns that may be suitable, such as Active Object, Proactor, and Reactor. The examples are C++, but there are diagrams and descriptions that will be helpful if you pursue your own implementation.
The proactor may provide an elegant solution or serve as the foundation for another pattern. For C++ implementations, I would recommend the boost::asio library:
Fairly well documented and examples.
SSL support.
The HTTP Server 3 example shows how to use boost::asio with a thread pool.
If you do not want a dependency on boost, then the asio library is also packaged separately here. For more patterns and information, consider this book.
Your question requires more than just a stack overflow question. You can find good ideas in these book:
Basically what you're trying to do is a
reactor
. You can find open source library implementing this pattern. For instance:If you want yout handler to have the possibility to do more processing you could give them a reference to your TCPServer and a way to register a socket for the following events:
read
, the socket is ready for readwrite
, the socket is ready for writeaccept
, the listening socket is ready to accept (read withselect
)close
, the socket is closedtimeout
, the time given to wait for the next event expired (select
allow to specify a timeout)So that the handler can implement all kinds of protocols
half-duplex
orfull-duplex
:write
event to let a handler knows when it can send on the socket.read
event. It should not be in your main loop but in the socketread
handler.timeout
so that you can implementtimers
and drop idle connections.This leads to some problems:
state-machine
to react to the network events and update the events it wants to receive.queue
of messages. The queue is needed because the readiness of one socket is independent of the readiness of the other. And you may read something on one and not being ready to send it on the other.priority queue
for timeoutsAs you see this is no simple problem. You may want to reduce the genericity of your framework to simplify its design. (for instance handling only
half-duplex
protocols like simple HTTP)The solution to your problem is to use lock-free algorithms allowing for system wide progress of at least one task. You need to use inline assembler that is CPU dependent to make sure that you atomic CAS (compare-and-swap). Wikipedia has an article as well as patterns described the the book by Douglas Schmidt called "Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects". It is not immediately clear to me how you will do that under the dotnet framework.
Other way of solving your problem is using the publish-subscriber pattern or possible thread pools.
Hope this was helpful?
Using asynchronous communication is totally possible in single thread!
There is a common design pattern in network software development called the reactor pattern (look at this book). Some well known network library provides an implementation of this pattern (look at ACE).
Briefly, the reactor is an object, you register all your sockets inside, and you wait for something. If something happened (new data arrived, connection close...) the reactor will notify you. And of course, you can use only one socket to send and received data asynchronously.
You will hear discording opinions about design patterns, in the programming community at large.
In my opinion, it is sure that there are abstractions that patterns encapsulate that are really useful (factory, singleton, delegate, etc.). I use patterns a lot, but I myself am sometime puzzled by the apparent lack of depth or level of insight that you get by reading a pattern description. This is also in tune with the proliferation of design patterns that specialize for any kind of things.
When the design hey are useful, they are a very good means of communication and certainly they guide you through the process of designing or defining the architecture of your app. They are useful both for small project and for large ones, and they can be applied at different granularity levels.
Patters are a generic concept and all programming languages support them. Anyway, if you work in C++, a book focusing on it is best, because you will get the pattern adapted to the characteristics of the language.
In my opinion, the really fundamental book about design patterns are:
GoF, Design Patterns: Elements of Reusable Object-Oriented Software
VV.AA., Pattern-Oriented Software Architecture Volume 1: A System of Patterns
VV.AA., Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects
Some of the very best books in my never-ending quest to learn patterns:
There are numerous patterns that could solve the problem, but the key point in making the decision is understanding the pattern's consequences. The ACE website has some papers for some concurrency patterns that may be suitable, such as Active Object, Proactor, and Reactor. The examples are C++, but there are diagrams and descriptions that will be helpful if you pursue your own implementation.
The proactor may provide an elegant solution or serve as the foundation for another pattern. For C++ implementations, I would recommend the
boost::asio
library:boost::asio
with a thread pool.If you do not want a dependency on
boost
, then theasio
library is also packaged separately here. For more patterns and information, consider this book.