Basic network programming in .NET (part 2)
Since you're reading this, I'll assume the previous post didn't scare you off. I know even that abridged version of details may seem daunting but really, with some practice writing network code, it's all stuff that will come naturally. With that in mind, let's get to know what the basic structure of a network application looks like, and then practice!
In every network connection, there is an endpoint that is waiting ("listening") for someone to contact it, and an endpoint that does the contacting ("initiates the connection"). Once contact has been established, the roles of "server" and "client" can be less well-defined, but generally speaking the endpoint that's waiting is considered the "server" and the endpoint that doing the contacting is considered the "client".
With that in mind, here's the usual sequence of events:
- Server creates a socket for the purpose of waiting for contacts
- Client creates a socket for the purpose of contacting a server
- Client contacts the server
- Server responds
- Client and server exchange information by sending and receiving bytes
There are some subtle differences between UDP and TCP in the above. Using UDP, the "contact" is simply the transmission of a datagram to the server. Data exchange is done in exactly the same way as the initial contact, and there may be no well-defined termination of communications. In fact, each endpoint can use a single socket to communicate with an arbitrarily large number of remote endpoints.
With TCP, the initial contact is more explicit, in the form of a "connect" operation. The server's socket is a special type of socket that is never actually used for exchanging data. Instead, it acts as a kind of "connection factory", creating a new socket for each connection. For each client that connects to the server, the listening socket generates a socket that's actually used for exchanging data.
At each end, the socket associated with the actual connection can be used only for communicating with the remote endpoint of that connection. And TCP provides for a well-defined termination of communications, known as "graceful closure" or "graceful shutdown".
Of course, as mentioned previously, UDP is connectionless, it isn't reliable, and it always delivers data in the same unit (a datagram) as it was sent. But the basic techniques for moving data and managing the i/o generally are otherwise very similar to those used in TCP. For the sake of simplicity, I will stick mainly to TCP for code examples. Once I've gotten through the main samples, I'll wrap up with some that illustrate techniques specific to UDP: broadcast, and multicast.
For the next post, I'll describe the most basic code that can implement all of the above.