Recipe 16.1. Writing a TCP ServerProblemYou need to create a server that listens on a port for incoming requests from a TCP client. These client requests can then be processed at the server, and any responses can be sent back to the client. Recipe 16.2 shows how to write a TCP client to interact with this server. SolutionUse the MyTcpServer class created here to listen on a TCP-based endpoint for requests arriving on a given port: class MyTcpServer { #region Private Members private TcpListener _listener = null; private IPAddress _address; private int _port; private bool _listening = false; #endregion #region CTORs public MyTcpServer(IPAddress address, int port) { _port = port; _address = address; } #endregion // CTORs The TCPServer class has two properties:
These return the current address and port on which the server is listening and the listening state: #region Properties public IPAddress Address { get { return _address; } } public int Port { get { return _port; } } public bool Listening { get { return _listening; } } #endregion The Listen method tells the MyTcpServer class to start listening on the specified address and port combination. You create and start a TcpListener, then call its AcceptTcpClient method to wait for a client request to arrive. Once the client connects, a request is sent to the thread pool to service the client and that runs the ProcessClient method. The listener shuts down after serving the client: #region Public Methods public void Listen() { try { lock (_syncRoot) { _listener = new TcpListener(_address, _port); // Fire up the server _listener.Start(); // Set _listening bit _listening = true; } // Enter the _listening loop do { Trace.Write("Looking for someone to talk to… "); // Wait for connection TcpClient newClient = _listener.AcceptTcpClient(); Trace.WriteLine("Connected to new client"); // Queue a request to take care of the client ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessClient), newClient); } while (_listening); } catch (SocketException se) { Trace.WriteLine("SocketException: " + se.ToString()); } finally { // Shut it down StopListening(); } } The StopListening method is called to stop the TCPServer from listening for requests: public void StopListening() { if (_listening) { lock (_syncRoot) { // Set listening bit _listening = false; // Shut it down. _listener.Stop(); } } } #endregion The ProcessClient method shown in Example 16-1 executes on a thread-pool thread to serve a connected client. It gets the NetworkStream from the client using the TcpClient.GetStream method, then reads the whole request. After sending back a response, it shuts down the client connection. Example 16-1. ProcessClient method
A simple server that listens for clients until the Escape key is pressed might look like the following code: class Program { static MyTcpServer server = null; static void Main(string[] args) { // Run the server on a different thread ThreadPool.QueueUserWorkItem(RunServer); Console.WriteLine("Press Esc to stop the server…"); ConsoleKeyInfo cki; while(true) { cki = Console.ReadKey(); if (cki.Key == ConsoleKey.Escape) break; } } static void RunServer( object stateInfo ) { // Fire it up server = new MyTcpServer(IPAddress.Loopback,55555); server.Listen(); } } When talking to the MyTcpClient class in Recipe 16.2, the output for the server looks like this: Press Esc to stop the server… Looking for someone to talk to… Connected to new client Looking for someone to talk to… Client says: Just wanted to say hi Connected to new client Looking for someone to talk to… Client says: Just wanted to say hi again Connected to new client Looking for someone to talk to… Client says: Are you ignoring me? Connected to new client Looking for someone to talk to… Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 0) Client says: I'll not be ignored! (round 1) Connected to new client Looking for someone to talk to… Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 2) Client says: I'll not be ignored! (round 3) Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 4) Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 5) Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 6) Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 7) Connected to new client Looking for someone to talk to… Client says: I'll not be ignored! (round 8) [more output follows…] DiscussionThe Transmission Control Protocol (TCP) is the protocol used by the majority of traffic on the Internet today. TCP is responsible for the correct delivery of data packets from one endpoint to another. It uses the Internet Protocol (IP) to make the delivery. IP handles getting the packets from node to node; TCP detects when packets are not correct, are missing, or are sent out of order, and it arranges for missing or damaged packets to be resent. The TCPServer class is a basic server mechanism for dealing with requests that come from clients over TCP. MyTcpServer takes the IP address and port passed in then in the Listen method and creates a TcpListener on that IPAddress and port. Once created, the TcpListener.Start. method is called to start up the server. The blocking AcceptTcpClient method is called to listen for requests from TCP-based clients. Once the client connects, the ProcessClient method is executed. In this method, the server reads request data from the client and returns a brief acknowledgment. The server disconnects from the client by calling NetworkStream.Close and TcpClient.Close. The server stops listening when the StopListening method is called. StopListening takes the server offline by calling TcpListener.Stop. See AlsoSee the "IPAddress Class," "TcpListener Class," and "TcpClient Class" topics in the MSDN documentation. |