The TcpListener Class





The TcpListener Class

Like TcpClient, the TcpListener class (also located in the System.Net.Sockets namespace) provides a simplified way to create TCP server applications. This section describes the TcpListener class and shows how to use it in a simple TCP server application.

The TcpListener Class Constructors

The TcpListener class has three constructor formats:

TcpListener(int port) This constructor binds to a specific local port number.

TcpListener(IPEndPoint ie) This constructor binds to a specific local EndPoint object. TcpListener(IPAddress addr, int port)

TcpListener(IPAddress addr, int port) This constructor binds to a specific local IPAddress object and port number.

Unlike TcpClient, the TcpListener class constructor requires at least one parameter: the port number on which to listen for new connections. If the server machine has multiple network cards and you want to listen on a specific one, you can use an IPEndPoint object to specify the IP address of the desired card, along with the desired TCP port number to listen on. The constructor described last in the list just above allows you to specify the desired IP address using an IPAddress object, with the port number as a separate parameter.

The TcpListener Class Methods

The TcpListener class methods, listed in Figure, are used to perform the necessary functions on the created TcpListener object.

Figure: TcpListener Class Methods

Method

Description

AcceptSocket()

Accepts an incoming connection on the port and assign it to a Socket object

AcceptTcpClient()

Accepts an incoming connection on the port and assigns it to a TcpClient object

Equals()

Determines if two TcpListener objects are equal

GetHashCode()

Gets a hash code suitable for use in hash functions

GetType()

Gets the type of the current instance

Pending()

Determines if there are pending connection requests

Start()

Starts listening for connection attempts

Stop()

Stops listening for connection attempts (closes the socket)

ToString()

Creates a string representation of the TcpListener object

The procedure to create a TcpListener object and listen for incoming connections goes like this:

TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 9050);
server.Start();
TcpClient newclient = server.AcceptTcpClient();

The Start() method is similar to the combination of Bind() and Listen() used in the Socket class. Start() binds the socket to the endpoint defined in the TcpListener constructor and places the TCP port in listen mode, ready to accept new connections. The AcceptTcpClient() method is comparable to the Accept() socket method, accepting incoming connection attempts and assigning them to a TcpClient object.

After the TcpClient object is created, all communication with the remote device is performed with the new TcpClient object rather than the original TcpListener object. The TcpListener object can thus be used to accept other connections and pass them to other TcpClient objects. To close the TcpListener object, you must use the Stop() method:

server.Stop();
Note 

If you have any open client connections, you do not have to close them before the original TcpListener object is closed. However, you do have to remember to close the individual TcpClient objects using the Close() method.

A Simple Server Program

Now let’s look at a simple example of a TCP server using the TcpListener class. This example, TcpListenerSample.cs in Listing 7.2, mimics the functionality of the original SimpleTcpSrvr program presented in Chapter 5 (Listing 5.1).

Listing 7.2: The TcpListenerSample.cs program
Start example
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class TcpListenerSample
{
  public static void Main()
  {
   int recv;
   byte[] data = new byte[1024];
   TcpListener newsock = new TcpListener(9050);
   newsock.Start();
   Console.WriteLine("Waiting for a client...");
   TcpClient client = newsock.AcceptTcpClient();
   NetworkStream ns = client.GetStream();
   string welcome = "Welcome to my test server";
   data = Encoding.ASCII.GetBytes(welcome);
   ns.Write(data, 0, data.Length);
   while(true)
   {
     data = new byte[1024];
     recv = ns.Read(data, 0, data.Length);
     if (recv == 0)
      break;
   
     Console.WriteLine(
         Encoding.ASCII.GetString(data, 0, recv));
     ns.Write(data, 0, recv);
   }
   ns.Close();
   client.Close();
   newsock.Stop();
  }
}
End example

The TcpListenerSample program first creates a TcpListener object, using a UDP port of 9050, and the Start() method places the new object in a listening mode. Then the AcceptTcpClient() method waits for an incoming TCP connection and requests and assigns it to a TcpClient object:

TcpListener newsock = new TcpListener(9050);
newsock.Start();
TcpClient client = newsock.AcceptTcpClient();
NetworkStream ns = client.GetStream();

With the TcpClient object established, a NetworkStream object is assigned to it to communicate with the remote client. All communication is done using the NetworkStream object’s Read() and Write() methods. Remember to place all data into a byte array for the Write() method. Likewise, all received data from the Read() method must also be assigned to a byte array.

You can test the TcpListenerSample program by starting it up and connecting to it with the TcpClientSample program from the preceding section. They should behave together exactly like the SimpleTcpSrvr (Listing 5.1) and SimpleTcpClient (Listing 5.2) programs from Chapter 5. As usual, if you are testing these programs across a network, you can use the WinDump and Analyzer programs to watch the network traffic generated by each program.

Incorporating the StreamReader and StreamWriter Classes

Because the NetworkStream object uses streams to transfer data among the network hosts, you will have to handle the usual problems of identifying messages in the stream. Use the standard techniques outlined in Chapter 5 to delimit messages within the stream:

  • Send fixed-size messages

  • Send the message size before the message

  • Use message delimiter characters

After it’s created from the TcpClient object, you can use the NetworkStream object to create StreamReader and StreamWriter objects. (This is demonstrated in the "Using C# Streams with

TCP” section of Chapter 5.) These objects will automatically create message delimiters to simplify moving text across the network:

TcpClient client = new TcpClient("127.0.0.1", 9050);
NetworkStream ns = client.GetStream();
StreamReader sr = new StreamReader(ns);
StreamWriter sw = new StreamWriter(ns);
sw.WriteLine("This is a test");
sw.Flush();
string data = sr.ReadLine();

The StreamReader and StreamWriter classes by default use a line feed to delimit messages, which makes it a snap to distinguish[ messages in TCP communications. Because the ReadLine() and WriteLine() methods both use String objects, text messages can be created and sent using the String class objects instead of your having to mess with the bulky data-byte arrays.


 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows