Up to this point, we have discussed connection-oriented, streams-based transmissions using the TCP protocol to ensure that the packets of data are transmitted reliably. Now, we consider connectionless transmission using datagrams and UDP.
Connectionless transmission via datagrams resembles the method by which the postal service carries and delivers mail. Connectionless transmission bundles and sends information in packets called datagrams, which can be thought of as similar to letters you send through the mail. If a large message will not fit in one envelope, that message is broken into separate message pieces and placed in separate, sequentially numbered envelopes. All the letters are mailed at once. The letters might arrive in order, out of order or not at all. The person at the receiving end reassembles the message pieces in sequential order before attempting to interpret the message. If the message is small enough to fit in one envelope, the sequencing problem is eliminated, but it is still possible that the message will never arrive. (Unlike with postal mail, duplicate of datagrams could reach receiving computers.) C# provides the UdpClient class for connectionless transmission. Like TcpListener and TcpClient, UdpClient uses methods from class Socket. The UdpClient methods Send and Receive transmit data with Socket's SendTo method and read data with Socket's ReceiveFrom method, respectively.
The programs in Fig. 23.3 and Fig. 23.4 use datagrams to send packets of information between client and server applications. In the PacketClient application, the user types a message into a TextBox and presses Enter. The client converts the message to a byte array and sends it to the server. The server receives the packet and displays the packet's information, then echoes, or returns, the packet to the client. When the client receives the packet, the client displays the packet's information. In this example, the implementations of the PacketClientForm and PacketServerForm classes are similar.
Figure 23.3. Server-side portion of connectionless client/server computing.
(This item is displayed on pages 1248 - 1249 in the print version)
1 // Fig. 23.3: PacketServer.cs 2 // Set up a server that will receive packets from a 3 // client and send the packets back to the client. 4 using System; 5 using System.Windows.Forms; 6 using System.Net; 7 using System.Net.Sockets; 8 using System.Threading; 9 10 public partial class PacketServerForm : Form 11 { 12 public PacketServerForm() 13 { 14 InitializeComponent(); 15 } // end constructor 16 17 private UdpClient client; 18 private IPEndPoint receivePoint; 19 20 // initialize variables and thread for receiving packets 21 private void PacketServerForm_Load( object sender, EventArgs e ) 22 { 23 client = new UdpClient( 50000 ); 24 receivePoint = new IPEndPoint( new IPAddress( 0 ), 0 ); 25 Thread readThread = 26 new Thread( new ThreadStart( WaitForPackets ) ); 27 readThread.Start(); 28 } // end method PacketServerForm_Load 29 30 // shut down the server 31 private void PacketServerForm_FormClosing( object sender, 32 FormClosingEventArgs e ) 33 { 34 System.Environment.Exit( System.Environment.ExitCode ); 35 } // end method PacketServerForm_FormClosing 36 37 // delegate that allows method DisplayMessage to be called 38 // in the thread that creates and maintains the GUI 39 private delegate void DisplayDelegate( string message ); 40 41 // method DisplayMessage sets displayTextBox's Text property 42 // in a thread-safe manner 43 private void DisplayMessage( string message ) 44 {45 // if modifying displayTextBox is not thread safe 46 if ( displayTextBox.InvokeRequired ) 47 { 48 // use inherited method Invoke to execute DisplayMessage 49 // via a delegate 50 Invoke( new DisplayDelegate( DisplayMessage ), 51 new object[] { message } ); 52 } // end if 53 else // OK to modify displayTextBox in current thread 54 displayTextBox.Text += message; 55 } // end method DisplayMessage 56 57 // wait for a packet to arrive 58 public void WaitForPackets() 59 { 60 while ( true ) 61 { 62 // set up packet 63 byte[] data = client.Receive( ref receivePoint ); 64 DisplayMessage( " Packet received:" + 65 " Length: " + data.Length + 66 " Containing: " + 67 System.Text.Encoding.ASCII.GetString( data ) ); 68 69 // echo information from packet back to client 70 DisplayMessage( " Echo data back to client..." ); 71 client.Send( data, data.Length, receivePoint ); 72 DisplayMessage( " Packet sent " ); 73 } // end while 74 } // end method WaitForPackets 75 } // end class PacketServerForm |
Figure 23.4. Client portion of connectionless client/server computing.
(This item is displayed on pages 1250 - 1252 in the print version)
1 // Fig. 23.4: PacketClient.cs 2 // Set up a client that sends packets to a server and receives 3 // packets from a server. 4 using System; 5 using System.Windows.Forms; 6 using System.Net; 7 using System.Net.Sockets; 8 using System.Threading; 9 10 public partial class PacketClientForm : Form 11 { 12 public PacketClientForm() 13 { 14 InitializeComponent(); 15 } // end constructor 1617 private UdpClient client; 18 private IPEndPoint receivePoint; 19 20 // initialize variables and thread for receiving packets 21 private void PacketClientForm_Load( object sender, EventArgs e ) 22 { 23 receivePoint = new IPEndPoint( new IPAddress( 0 ), 0 ); 24 client = new UdpClient( 50001 ); 25 Thread thread = 26 new Thread( new ThreadStart( WaitForPackets ) ); 27 thread.Start(); 28 } // end method PacketClientForm_Load 29 30 // shut down the client 31 private void PacketClientForm_FormClosing( object sender, 32 FormClosingEventArgs e ) 33 { 34 System.Environment.Exit( System.Environment.ExitCode ); 35 } // end method PacketClientForm_FormClosing 36 37 // delegate that allows method DisplayMessage to be called 38 // in the thread that creates and maintains the GUI 39 private delegate void DisplayDelegate( string message ); 40 41 // method DisplayMessage sets displayTextBox's Text property 42 // in a thread-safe manner 43 private void DisplayMessage( string message ) 44 { 45 // if modifying displayTextBox is not thread safe 46 if ( displayTextBox.InvokeRequired ) 47 { 48 // use inherited method Invoke to execute DisplayMessage 49 // via a delegate 50 Invoke( new DisplayDelegate( DisplayMessage ), 51 new object[] { message } ); 52 } // end if 53 else // OK to modify displayTextBox in current thread 54 displayTextBox.Text += message; 55 } // end method DisplayMessage 56 57 // send a packet 58 private void inputTextBox_KeyDown( object sender, KeyEventArgs e ) 59 { 60 if ( e.KeyCode == Keys.Enter ) 61 { 62 // create packet (datagram) as string 63 string packet = inputTextBox.Text; 64 displayTextBox.Text += 65 " Sending packet containing: " + packet; 66 67 // convert packet to byte array 68 byte[] data = System.Text.Encoding.ASCII.GetBytes( packet ); 69 70 // send packet to server on port 50000 71 client.Send( data, data.Length, "127.0.0.1", 50000 ); 72 displayTextBox.Text += " Packet sent "; 73 inputTextBox.Clear(); 74 } // end if 75 } // end method inputTextBox_KeyDown 76 77 // wait for packets to arrive 78 public void WaitForPackets() 79 { 80 while ( true ) 81 { 82 // receive byte array from server 83 byte[] data = client.Receive( ref receivePoint ); 84 85 // output packet data to TextBox 86 DisplayMessage( " Packet received:" + 87 " Length: " + data.Length + " Containing: " + 88 System.Text.Encoding.ASCII.GetString( data ) + " " ); 89 } // end while 90 } // end method WaitForPackets 91 } // end class PacketClientForm (a) Packet Client window before sending a packet to the server (b) Packet Client window after sending a packet to the server and receiving it back |
PacketServerForm Class
The code in Fig. 23.3 defines the PacketServerForm for this application. Line 23 in the Load event handler for class PacketServerForm creates an instance of the UdpClient class that receives data at port 50000. This initializes the underlying Socket for communications. Line 24 creates an instance of class IPEndPoint to hold the IP address and port number of the client(s) that transmit to PacketServerForm. The first argument to the IPEndPoint constructor is an IPAddress object; the second argument is the port number of the endpoint. These values are both 0, because we need only instantiate an empty IPEndPoint object. The IP addresses and port numbers of clients are copied into the IPEndPoint when datagrams are received from clients.
Lines 3955 define DisplayDelegate and DisplayMessage, allowing any thread to modify displayTextBox's Text property.
PacketServerForm method WaitForPackets (lines 5874) executes an infinite loop while waiting for data to arrive at the PacketServerForm. When information arrives, UdpClient method Receive (line 63) receives a byte array from the client. We pass to Receive the IPEndPoint object created in the constructorthis provides the method with an IPEndPoint to which the program copies the client's IP address and port number. This program will compile and run without an exception even if the reference to the IPEndPoint object is null, because method Receive initializes the IPEndPoint if it is null.
Lines 6467 update the PacketServerForm's display to include the packet's information and content. Line 71 echoes the data back to the client, using UdpClient method Send. This version of Send takes three argumentsthe byte array to send, an int representing the array's length and the IPEndPoint to which to send the data. We use array data returned by method Receive as the data, the length of array data as the length and the IPEndPoint passed to method Receive as the data's destination. The IP address and port number of the client that sent the data are stored in receivePoint, so merely passing receivePoint to Send allows PacketServerForm to respond to the client.
PacketClientForm Class
Class PacketClientForm (Fig. 23.4) works similarly to class PacketServerForm, except that the Client object sends packets only when the user types a message in a TextBox and presses the Enter key. When this occurs, the program calls event handler inputTextBox_KeyDown (lines 5875). Line 68 converts the string that the user entered in the TextBox to a byte array. Line 71 calls UdpClient method Send to send the byte array to the PacketServerForm that is located on localhost (i.e., the same machine). We specify the port as 50000, which we know to be PacketServerForm's port.
Lines 3955 define DisplayDelegate and DisplayMessage, allowing any thread to modify displayTextBox's Text property.
Line 24 instantiates a UdpClient object to receive packets at port 50001we choose port 50001 because the PacketServerForm already occupies port 50000. Method WaiForPackets of class PacketClientForm (lines 7890) uses an infinite loop to wait for these packets. UdpClient method Receive blocks until a packet of data is received (line 83). The blocking performed by method Receive does not prevent class PacketClientForm from performing other services (e.g., handling user input), because a separate thread runs method WaitForPackets.
When a packet arrives, lines 8688 display its contents in the TextBox. The user can type information in the PacketClientForm window's TextBox and press the Enter key at any time, even while a packet is being received. The event handler for the TextBox processes the event and sends the data to the server.
Client Server Tic Tac Toe Using a Multithreaded Server |
Preface
Index
Introduction to Computers, the Internet and Visual C#
Introduction to the Visual C# 2005 Express Edition IDE
Introduction to C# Applications
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Methods: A Deeper Look
Arrays
Classes and Objects: A Deeper Look
Object-Oriented Programming: Inheritance
Polymorphism, Interfaces & Operator Overloading
Exception Handling
Graphical User Interface Concepts: Part 1
Graphical User Interface Concepts: Part 2
Multithreading
Strings, Characters and Regular Expressions
Graphics and Multimedia
Files and Streams
Extensible Markup Language (XML)
Database, SQL and ADO.NET
ASP.NET 2.0, Web Forms and Web Controls
Web Services
Networking: Streams-Based Sockets and Datagrams
Searching and Sorting
Data Structures
Generics
Collections
Appendix A. Operator Precedence Chart
Appendix B. Number Systems
Appendix C. Using the Visual Studio 2005 Debugger
Appendix D. ASCII Character Set
Appendix E. Unicode®
Appendix F. Introduction to XHTML: Part 1
Appendix G. Introduction to XHTML: Part 2
Appendix H. HTML/XHTML Special Characters
Appendix I. HTML/XHTML Colors
Appendix J. ATM Case Study Code
Appendix K. UML 2: Additional Diagram Types
Appendix L. Simple Types
Index