Networking

The BCL includes a number of types that make accessing networked resources easy. Offering different levels of abstraction, these types allow an application to ignore much of the detail normally required to access networked resources, while retaining a high degree of control.

This section describes the core networking support in the BCL, and provides numerous examples leveraging the predefined classes. The types mentioned in this section all exist in the System.Net.RegularExpressions and System.Net.Sockets namespaces.

Network Programming Models

High-level access is performed using a set of types that implement a generic request/response architecture that is extensible to support new protocols. The implementation of this architecture in the BCL also includes HTTP-specific extensions to make interacting with web servers easy.

Should the application require lower-level access to the network, types exist to support the Transmission Control Protocol (TCP) and User Datagram Protocol (UDP). Finally, in situations where direct transport-level access is required, there are types that provide raw socket access.

Generic Request/Response Architecture

The request/response architecture is based on Uniform Resource Indicator (URI) and stream I/O, follows the factory design pattern, and makes good use of abstract types and interfaces.

A factory type (WebRequestFactory ) parses the URI and creates the appropriate protocol handler to fulfill the request.

Protocol handlers share a common abstract base type (WebRequest), which exposes properties that configure the request and methods used to retrieve the response.

Responses are also represented as types and share a common abstract base type (WebRequest) which exposes a NetworkStream, providing simple streams-based I/O and easy integration into the rest of the BCL.

This example is a simple implementation of the popular Unix snarf utility. It demonstrates the use of the WebRequest and WebResponse classes to retrieve the contents of a URI and print them to the console:

// Snarf.cs - compile with /r:System.Net.dll
// Run Snarf.exe <http-uri> to retrieve a web page
using System;
using System.IO;
using System.Net;
using System.Text;
class Snarf {
  static void Main(string[] args) {

    // Retrieve the data at the URL with an WebRequest ABC
    WebRequest req = WebRequestFactory.Create(args[0]);
    WebResponse resp = req.GetResponse( );

    // Read in the data, performing ASCII->Unicode encoding
    Stream s = resp.GetResponseStream( );
    StreamReader sr = new StreamReader(s, Encoding.ASCII);
    string doc = sr.ReadToEnd( );

    Console.WriteLine(doc); // Print result to console
  }
}

HTTP-Specific Support

The request/response architecture inherently supports protocol-specific extensions via the use of subtyping.

Since the WebRequestFactory creates and returns the appropriate handler type based on the URI, accessing protocol-specific features is as easy as downcasting the returned WebRequest object to the appropriate protocol-specific handler and accessing the extended functionality.

The BCL includes specific support for the HTTP protocol, including the ability to easily access and control elements of an interactive web session, such as the HTTP headers, user-agent strings, proxy support, user credentials, authentication, keep-alives, pipelining, and more.

This example demonstrates the use of the HTTP-specific request/response classes to control the user-agent string for the request and retrieve the server type:

// ProbeSvr.cs - compile with /r:System.Net.dll
// Run ProbeSvr.exe <servername> to retrieve the server type
using System;
using System.Net;
class ProbeSvr {
  static void Main(string[] args) {

    // Get instance of WebRequest ABC, convert to HttpWebRequest
    WebRequest req = WebRequestFactory.Create(args[0]);
    HttpWebRequest httpReq = (HttpWebRequest)req;

    // Access HTTP-specific features such as User-Agent
    httpReq.UserAgent = "CSPRProbe/1.0";

    // Retrieve response and print to console
    WebResponse resp = req.GetResponse( );
    HttpWebResponse httpResp = (HttpWebResponse)resp;
    Console.WriteLine(httpResp.Server);
  }
}

Adding New Protocol Handlers

Adding handlers to support new protocols is trivial: simply implement a new set of derived types based on WebRequest and WebResponse, implement the IWebRequestCreate interface on your WebRequest-derived type, and register it as a new protocol handler with the Web-RequestFactory at runtime. Once this is done, any code that uses the request/response architecture can access networked resources using the new URI format (and underlying protocol).

Using TCP, UDP, and Sockets

The System.Net.Sockets namespace includes types that provide protocol-level support for TCP and UDP. These types are built on the underlying Socket type, which is itself directly accessible for transport-level access to the network.

Two classes provide the TCP support: TCPListener and TCPClient. TCPListener listens for incoming connections, creating Socket instances that respond to the connection request. TCPClient connects to a remote host, hiding the details of the underlying socket in a Stream-derived type that allows stream I/O over the network.

A class called UDPClient provides the UDP support. UDPClient serves as both a client and a listener and includes multicast support, allowing individual datagrams to be sent and received as byte arrays.

Both the TCP and the UDP classes help to access the underlying network socket (represented by the Socket class). The Socket class is a thin wrapper over the native Windows sockets functionality and is the lowest level of networking accessible to managed code.

The following example is a simple implementation of the Quote of the Day (QUOTD) protocol, as defined by the IETF in RFC 865. It demonstrates the use of a TCP listener to accept incoming requests and the use of the lower-level Socket type to fulfill the request:

// QOTDListener.cs - compile with /r:System.Net.dll 
// Run QOTDListener.exe to service incoming QOTD requests
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class QOTDListener {
  static string[] quotes = 
{@"Sufficiently advanced magic is indistinguishable from technology --
Terry Pratchett",
 @"Sufficiently advanced technology is indistinguishable from magic --
 Arthur C Clarke" };
  static void Main( ) {

    // Start a TCP listener on port 17
    TCPListener l = new TCPListener(17);
    l.Start( );
    Console.WriteLine("Waiting for clients to connect");
    Console.WriteLine("Press Ctrl+C to quit...");
    int numServed = 1;
    while (true) {

      // Block waiting for an incoming socket connect request
      Socket s = l.Accept( );

      // Encode alternating quotes as bytes for sending 
      Char[] carr = quotes[numServed%2].ToCharArray( );
      Byte[] barr = Encoding.ASCII.GetBytes(carr);

      // Return data to client, then clean up socket & repeat
      s.Send(barr, barr.Length, 0);
      s.Shutdown(SocketShutdown.SdBoth);
      s.Close( );
      Console.WriteLine("{0} quotes served...", numServed++);
    }
  }
}

To test this example, run the listener and try connecting to port 17 on localhost using a telnet client. (Under Windows 2000, this can be done from the command line by entering: telnet localhost 17 ).

Notice the use of Socket.Shutdown and Socket.Close at the end of the while loop; this is required to flush and close the socket immediately, rather than wait for the garbage collector to finalize and collect unreachable Socket objects later.

Using DNS

The networking types in the base class library also support normal and reverse Domain Name System (DNS) resolution. Here’s an example using these types:

// DNSLookup.cs - compile with /r:System.Net.dll
// Run DNSLookup.exe <servername> to determine IP addresses
using System;
using System.Net;
class DNSLookup {
  static void Main(string[] args) {
    IPHostEntry he = DNS.GetHostByName(args[0]);
    IPAddress[] addrs = he.AddressList;
    foreach (IPAddress addr in addrs)
      Console.WriteLine(addr);
  }
}
..................Content has been hidden....................

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