11.8 Communicate Using TCP


Problem

You need to send data between two computers on a network using a TCP/IP connection.

Solution

One computer (the server) must begin listening using the System.Net.Sockets.TcpListener class. Once a connection is established, both computers can communicate using the System.Net.Sockets.TcpListener class.

Discussion

TCP is a reliable, connection-based protocol that allows two computers to communicate over a network. It provides built-in flow-control , sequencing, and error handling, which makes it very reliable and easy to program with.

To create a TCP connection, one computer must act as the server and start listening on a specific endpoint . (An endpoint is defined as an IP address, which identifies the computer and port number.) The other computer must act as a client and send a connection request to the endpoint on which the first computer is listening. Once the connection is established, the two computers can take turns exchanging messages. .NET makes this process easy through its stream abstraction. Both computers simply write to and read from a System.Net.Sockets.NetworkStream to transmit data.

Note  

Even though a TCP connection always requires a server and a client, there's no reason an individual application can't be both. For example, in a peer-to-peer application, one thread is dedicated to listening for incoming requests (acting as a server) while another thread is dedicated to initiate outgoing connections (acting as a client). In the examples provided with this chapter, the client and server are provided as separate applications and are placed in separate subdirectories. See the readme.txt included with the code for more information.

Once a TCP connection is established, the two computers can send any type of data by writing it to the NetworkStream . However, it's a good idea to begin designing a networked application by defining the application-level protocol that clients and servers will use to communicate. This protocol includes constants that represent the allowable commands, ensuring that your application code doesn't include hard-coded communication strings.

 namespace SharedComponent {     public class ServerMessages {         public const string AcknowledgeOK = "OK";         public const string AcknowledgeCancel = "Cancel";         public const string Disconnect = "Bye";     }     public class ClientMessages {         public const string RequestConnect = "Hello";         public const string Disconnect = "Bye";     } } 

In this example, the defined vocabulary is basic. You would add more constants depending on the type of application. For example, in a file transfer application, you might include a client message for requesting a file. The server might then respond with an acknowledgment and return file details such as the file size . These constants should be compiled into a separate class library assembly, which must be referenced by both the client and server.

The following code is a template for a basic TCP server. It listens on a fixed port, accepts the first incoming connection, and then waits for the client to request a disconnect. At this point, the server could call the TcpListener.AcceptTcpClient method again to wait for the next client, but instead, it simply shuts down.

 using System; using System.Net; using System.Net.Sockets; using System.IO; using SharedComponent; public class TcpServerTest {     private static void Main() {         // Create a new listener on port 8000.         TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"),            8000);                      Console.WriteLine("About to initialize port.");         listener.Start();         Console.WriteLine("Listening for a connection...");                      try {             // Wait for a connection request,              // and return a TcpClient initialized for communication.              TcpClient client = listener.AcceptTcpClient();             Console.WriteLine("Connection accepted.");                              // Retrieve the network stream.             NetworkStream stream = client.GetStream();             // Create a BinaryWriter for writing to the stream.             BinaryWriter w = new BinaryWriter(stream);                              // Create a BinaryReader for reading from the stream.             BinaryReader r = new BinaryReader(stream);                              if (r.ReadString() == ClientMessages.RequestConnect) {                 w.Write(ServerMessages.AcknowledgeOK);                 Console.WriteLine("Connection completed.");                                      while (r.ReadString() != ClientMessages.Disconnect)                 {}                 Console.WriteLine();                 Console.WriteLine("Disconnect request received.");                 w.Write(ServerMessages.Disconnect);             } else {                 Console.WriteLine("Could not complete connection.");             }             // Close the connection socket.             client.Close();             Console.WriteLine("Connection closed.");             // Close the underlying socket (stop listening for new requests).             listener.Stop();             Console.WriteLine("Listener stopped.");         } catch (Exception err) {             Console.WriteLine(err.ToString());         }                  Console.ReadLine();     } } 

The following code is a template for a basic TCP client. It contacts the server at the specified IP address and port. In this example, the loopback address (127.0.0.1) is used, which always points to the current computer. Keep in mind that a TCP connection requires two ports: one at the server end and one at the client end. However, only the server port needs to be specified. The client port can be chosen dynamically at run time from the available ports, which is what the TcpClient class will do by default.

 using System; using System.Net; using System.Net.Sockets; using System.IO; using SharedComponent; public class TcpClientTest {     private static void Main() {         TcpClient client = new TcpClient();         try {             Console.WriteLine("Attempting to connect to the server " +               "on port 8000.");             client.Connect(IPAddress.Parse("127.0.0.1"), 8000);             Console.WriteLine("Connection established.");             // Retrieve the network stream.             NetworkStream stream = client.GetStream();             // Create a BinaryWriter for writing to the stream.             BinaryWriter w = new BinaryWriter(stream);                              // Create a BinaryReader for reading from the stream.             BinaryReader r = new BinaryReader(stream);                              // Start a dialogue.             w.Write(ClientMessages.RequestConnect);             if (r.ReadString() == ServerMessages.AcknowledgeOK) {                 Console.WriteLine("Connected.");                 Console.WriteLine("Press Enter to disconnect.");                 Console.ReadLine();                 Console.WriteLine("Disconnecting...");                 w.Write(ClientMessages.Disconnect);             } else {                 Console.WriteLine("Connection not completed.");             }             // Close the connection socket.             client.Close();             Console.WriteLine("Port closed.");         } catch (Exception err) {             Console.WriteLine(err.ToString());         }                  Console.ReadLine();     } } 

Here's a sample connection transcript on the server side:

 About to initialize port. Listening for a connection... Connection accepted. Connection completed. Disconnect request received. Connection closed. Listener stopped. 

And here's a sample connection transcript on the client side:

 Attempting to connect to the server on port 8000. Connection established. Connected. Press Enter to disconnect. Disconnecting... Port closed. 



C# Programmer[ap]s Cookbook
C# Programmer[ap]s Cookbook
ISBN: 735619301
EAN: N/A
Year: 2006
Pages: 266

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