5.9. System.Net.Sockets

The System.Net.Sockets namespace provides a Socket class encapsulating Windows Sockets functionality. Transmission Control Protocol (TCP) support is provided by the TcpListener and TcpClient classes. To illustrate how we can use these classes, we'll create a client/server phone directory from the sample Northwind SQL database. On separate threads, the server retrieves the database information and sets up a TcpListener object to accept incoming requests. The client creates a TcpClient object, acquires a NetworkStream object, and then packages and sends a request over the network. A client session is pictured in Figure 5.1. The port number of the client request is displayed in square brackets. The server line with the phone number is data received across a NetworkStream from the TcpListener.

Figure 5.1. Client Side of Socket Example


A server session handling three incoming requests is pictured in Figure 5.2. The server start-up traces the various operations, including the starting of the TcpListener and retrieving the SQL database information. The port number of the server is displayed in square brackets. Let's solve the server-side implementation first.

Figure 5.2. Server Side of Socket Example


5.9.1. The Server-Side TcpListener

TcpListener is a class object that listens for connections from TCP clients. The first step is to create an instance; in our case we pass the constructor a port number. This is the same port to which clients direct their requests. Once the object has been constructed, we invoke its Start() method to have it begin listening for incoming requests—for example,

public class SocketDemo_Server
{
   static private int port = 4554;
   private TcpListener       tcpl;

public SocketDemo_Server()
{
   // start listening on the assigned port
   tcpl = new TcpListener(port) ;
   tcpl.Start();

The next step is to implement the connection logic to handle an incoming request. In this case we expect the input to represent an individual's last name. We'll grab the data, clean it up a bit, and attempt to retrieve a phone number associated with the name. We'll then package our response and send it back to the client. Let's see how we do that.

The client is ephemeral. It comes into existence to post its request, then to wait for and handle the response. Once that is done, the client is generally done and exits. The server, on the other hand, can run as long as the host machine is running. This means that it must continually poll to discover if a connection has docked in the port. The AcceptSocket() member function serves as a poll mechanism. It blocks on the call until a client connects; at that point it returns a Socket connection object. Here is that portion of the code:

public void handleConnection()
{
      while( true )
      {
            // blocks until a client connects

            Socket aSocket = tcpl.AcceptSocket();
            if( aSocket.Connected ) {

Next a byte array is created to receive the client's data. We pass it to the Receive() member function of the Socket class, together with the size of the array, and the index identifying where to begin placing the data. Receive() returns the number of bytes transferred. The byte array is converted into a string. We toss away any extraneous filler characters within it:

Byte [] packetBuffer = new Byte[ maxPacket ];
int byteCnt =
    aSocket.Receive( packetBuffer, packetBuffer.Length, 0 );

string clientPacket =
       Text.Encoding.ASCII.GetString( packetBuffer );

// get rid of unused buffer space ...
char [] unusedBytes = { (char)clientPacket[ byteCnt ] };
clientPacket = clientPacket.TrimEnd( unusedBytes );

Once the request has been processed, the next step is to package the result and return it to the client. The response is built up as a string then turned into a byte array and passed to the Send() member function of the Socket class:

Byte [] resultBuffer =
        Text.Encoding.ASCII.GetBytes( response.ToCharArray() );
aSocket.Send( resultBuffer, resultBuffer.Length, 0 );

The code sequence we've walked through here represents a complete handling of the client connection. The while loop reevaluates, and TcpListener again invokes AcceptSocket(), waiting for the next client connection.

5.9.2. The Client-Side TcpClient

TcpClient is a class object that provides network connection to a specified port on a specified host. In our example the TcpClient object is initialized with the host name and port. The connection is made implicitly within the constructor. Following that, we invoke TcpClient's GetStream() method to retrieve a NetworkStream object. All data between the client and server goes through this NetworkStream object—for example,

public class SocketDemo_Client
{
      private TcpClient tcpc;
      private static int port = 4554;
      private static string host = "localhost";
      public bool sendRequest( string data )
      {
            tcpc = new TcpClient( host, port);
            NetworkStream netstream = tcpc.GetStream();

Next we have to prepare the data we wish to transmit. As we did with our server-side implementation, we create a byte array. We invoke Write(), passing in the array, a beginning index, and a count of bytes to be transmitted:

Byte[] outPacket =
       Text.Encoding.ASCII.GetBytes( data.ToCharArray() );

netstream.Write( outPacket, 0, outPacket.Length );
netstream.Flush();

Following the transmission, we wait until data is available on the NetworkStream, polling on the DataAvailable property. When data is available, we again create a byte array to receive it. We then pass it to the Read() function, together with the size of the packet, and a beginning index. Finally, we convert the data received within the array into a string and display it on the console:

while( ! netstream.DataAvailable )
{
   byte[] packet = new byte[ max_packet ];
   int byteCnt = netstream.Read( packet, 0, max_packet );

   string dataRcd = Text.Encoding.ASCII.GetString( packet );
   Console.WriteLine( dataRcd );

   break;
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.31.163