Recipe16.1.Writing a TCP Server


Recipe 16.1. Writing a TCP Server

Problem

You 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.

Solution

Use 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:

  • Address, an IPAddress

  • Port, an int

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

 #region Private Methods private void ProcessClient(object client) {     TcpClient newClient = (TcpClient)client;     try     {         // Buffer for reading data         byte[] bytes = new byte[1024];         StringBuilder clientData = new StringBuilder();         // Get the stream to talk to the client over         using (NetworkStream ns = newClient.GetStream())         {             // Set initial read timeout to 1 minute to allow for connection             ns.ReadTimeout = 60000;             // Loop to receive all the data sent by the client             int bytesRead = 0;             do             {                 // Read the data                 try                 {                     bytesRead = ns.Read(bytes, 0, bytes.Length);                     if (bytesRead > 0)                     {                         // Translate data bytes to an ASCII string and append.                          clientData.Append(                             Encoding.ASCII.GetString(bytes, 0, bytesRead));                          // Decrease read timeout to 1 second now                          // that data is coming in.                          ns.ReadTimeout = 1000;                     }                 }                 catch (IOException ioe)                 {                     // Read timed out; all data has been retrieved                     Trace.WriteLine("Read timed out: " + ioe.ToString());                      bytesRead = 0;                 }             }             while (bytesRead > 0);             Trace.WriteLine("Client says: " + clientData.ToString());             // Thank them for their input.              bytes = Encoding.ASCII.GetBytes("Thanks call again!");             // Send back a response             ns.Write(bytes, 0, bytes.Length);         }     }     finally     {         // Stop talking to client         if(newClient != null)             newClient.Close();     } } #endregion } 

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…] 

Discussion

The 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 Also

See the "IPAddress Class," "TcpListener Class," and "TcpClient Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net