470 likes | 481 Views
Learn the fundamentals of networking technologies, client-server interactions, and socket-based communications. Establish simple servers and clients, and explore client/server interaction using stream sockets and datagrams. Master multithreaded servers for efficient communication.
E N D
Chapter 22 – Networking: Streams-Based Sockets and Datagrams Outline22.1 Introduction22.2 Establishing a Simple Server (Using Stream Sockets)22.3 Establishing a Simple Client (Using Stream Sockets)22.4 Client/Server Interaction with Stream-Socket Connections22.5 Connectionless Client/Server Interaction with Datagrams22.6 Client/Server Tic-Tac-Toe Using a Multithreaded Server
22.1 Introduction • Information system • The Internet • Networking technologies • Client-server relationship • Socket-based communications • Stream sockets • Packet-based communications • Datagram sockets
22.2 Establishing a Simple Server (Using Stream Sockets) • Five step process: • Create an object of TcpListener • Binds server to port number • Call Start method • Begin connection request • Make connection between server and client • Returns a Socket object • Processing phase • Methods Receive and Send • Connection-termination phase • Method Close • Multithreaded servers
22.3 Establishing a Simple Client (Using Stream Sockets) • Four step process: • Create object of TcpClient • Method Connect • Get a NetworkStream • WriteByte and ReadByte • Processing phase • Client and server communicate • Close connection • Method Close
22.4 Client/Server Interaction with Steam-Socket Connections • Client/server application • Client request connection • Server application sends array of bytes • Communicate visually via TextBoxes
1 // Fig. 22.1: Server.cs 2 // Set up a Server that will receive a connection from a client, 3 // send a string to the client, and close the connection. 4 5 using System; 6 using System.Drawing; 7 using System.Collections; 8 using System.ComponentModel; 9 using System.Windows.Forms; 10 using System.Threading; 11 using System.Net.Sockets; 12 using System.IO; 13 14 // server that awaits client connections (one at a time) and 15 // allows a conversation between client and server 16 public class Server : System.Windows.Forms.Form 17 { 18 private System.Windows.Forms.TextBox inputTextBox; 19 private System.Windows.Forms.TextBox displayTextBox; 20 private Socket connection; 21 private Thread readThread; 22 23 private System.ComponentModel.Container components = null; 24 private NetworkStream socketStream; 25 private BinaryWriter writer; 26 private BinaryReader reader; 27 28 // default constructor 29 public Server() 30 { 31 InitializeComponent(); 32 Server.cs
Will invoke method RunServer Thread will accept connections from clients Terminate all threads Method Exit closes all thread associated with application Read strings and send via method Write 33 // create a new thread from the server 34 readThread = new Thread( new ThreadStart( RunServer ) ); 35 readThread.Start(); 36 } 37 38 // Visual Studio .NET generated code 39 40 [STAThread] 41 static void Main() 42 { 43 Application.Run( new Server() ); 44 } 45 46 protected void Server_Closing( 47 object sender, CancelEventArgs e ) 48 { 49 System.Environment.Exit( System.Environment.ExitCode ); 50 } 51 52 // sends the text typed at the server to the client 53 protected void inputTextBox_KeyDown( 54 object sender, KeyEventArgs e ) 55 { 56 // sends the text to the client 57 try 58 { 59 if ( e.KeyCode == Keys.Enter && connection != null ) 60 { 61 writer.Write( "SERVER>>> " + inputTextBox.Text ); 62 63 displayTextBox.Text += 64 "\r\nSERVER>>> " + inputTextBox.Text; 65 Server.cs
TcpListener to pick request from user at port 5000 Gets TcpListener to begin waiting for requests Infinite loop to establish connection request by clients 66 // if the user at the server signaled termination 67 // sever the connection to the client 68 if ( inputTextBox.Text == "TERMINATE" ) 69 connection.Close(); 70 71 inputTextBox.Clear(); 72 } 73 } 74 catch ( SocketException ) 75 { 76 displayTextBox.Text += "\nError writing object"; 77 } 78 } // inputTextBox_KeyDown 79 80 // allows a client to connect and displays the text it sends 81 public void RunServer() 82 { 83 TcpListener listener; 84 int counter = 1; 85 86 // wait for a client connection and display the text 87 // that the client sends 88 try 89 { 90 // Step 1: create TcpListener 91 listener = new TcpListener( 5000 ); 92 93 // Step 2: TcpListener waits for connection request 94 listener.Start(); 95 96 // Step 3: establish connection upon client request 97 while ( true ) 98 { 99 displayTextBox.Text = "Waiting for connection\r\n"; 100 Server.cs
Returns a Socket upon successful connection Pass the new socket as argument to NetworkStream For use with writing or reading data Indicate that a connection was received Execute until server receive connection termination 101 // accept an incoming connection 102 connection = listener.AcceptSocket(); 103 104 // create NetworkStream object associated with socket 105 socketStream = new NetworkStream( connection ); 106 107 // create objects for transferring data across stream 108 writer = new BinaryWriter( socketStream ); 109 reader = new BinaryReader( socketStream ); 110 111 displayTextBox.Text += "Connection " + counter + 112 " received.\r\n"; 113 114 // inform client that connection was successfull 115 writer.Write( "SERVER>>> Connection successful" ); 116 117 inputTextBox.ReadOnly = false; 118 string theReply = ""; 119 120 // Step 4: read String data sent from client 121 do 122 { 123 try 124 { 125 // read the string sent to the server 126 theReply = reader.ReadString(); 127 128 // display the message 129 displayTextBox.Text += "\r\n" + theReply; 130 } 131 Server.cs
Close connection between client and server and waits for next request 132 // handle exception if error reading data 133 catch ( Exception ) 134 { 135 break; 136 } 137 138 } while ( theReply != "CLIENT>>> TERMINATE" && 139 connection.Connected ); 140 141 displayTextBox.Text += 142 "\r\nUser terminated connection"; 143 144 // Step 5: close connection 145 inputTextBox.ReadOnly = true; 146 writer.Close(); 147 reader.Close(); 148 socketStream.Close(); 149 connection.Close(); 150 151 ++counter; 152 } 153 } // end try 154 155 catch ( Exception error ) 156 { 157 MessageBox.Show( error.ToString() ); 158 } 159 160 } // end method RunServer 161 162 } // end class Server Server.cs
1 // Fig. 22.2: Client.cs 2 // Set up a Client that will read information sent from a Server 3 // and display the information. 4 5 using System; 6 using System.Drawing; 7 using System.Collections; 8 using System.ComponentModel; 9 using System.Windows.Forms; 10 using System.Threading; 11 using System.Net.Sockets; 12 using System.IO; 13 14 // connects to a chat server 15 public class Client : System.Windows.Forms.Form 16 { 17 private System.Windows.Forms.TextBox inputTextBox; 18 private System.Windows.Forms.TextBox displayTextBox; 19 20 private NetworkStream output; 21 private BinaryWriter writer; 22 private BinaryReader reader; 23 24 privatestring message = ""; 25 26 private Thread readThread; 27 28 private System.ComponentModel.Container components = null; 29 Client.cs
Like Server object, Client object creates Thread to handling incoming messages 30 // default constructor 31 public Client() 32 { 33 InitializeComponent(); 34 35 readThread = new Thread( new ThreadStart( RunClient ) ); 36 readThread.Start(); 37 } 38 39 // Visual Studio .NET-generated code 40 41 [STAThread] 42 static void Main() 43 { 44 Application.Run( new Client() ); 45 } 46 47 protected void Client_Closing( 48 object sender, CancelEventArgs e ) 49 { 50 System.Environment.Exit( System.Environment.ExitCode ); 51 } 52 53 // sends text the user typed to server 54 protected void inputTextBox_KeyDown ( 55 object sender, KeyEventArgs e ) 56 { 57 try 58 { 59 if ( e.KeyCode == Keys.Enter ) 60 { 61 writer.Write( "CLIENT>>> " + inputTextBox.Text ); 62 Client.cs
Method to connect and receive data from the Server and send data to the Server Port number must match port number set for connection on server Method Connect used to establish connection Also considered the loopback IP address First argument is name of the server 63 displayTextBox.Text += 64 "\r\nCLIENT>>> " + inputTextBox.Text; 65 66 inputTextBox.Clear(); 67 } 68 } 69 catch ( SocketException ioe ) 70 { 71 displayTextBox.Text += "\nError writing object"; 72 } 73 74 } // end method inputTextBox_KeyDown 75 76 // connect to server and display server-generated text 77 public void RunClient() 78 { 79 TcpClient client; 80 81 // instantiate TcpClient for sending data to server 82 try 83 { 84 displayTextBox.Text += "Attempting connection\r\n"; 85 86 // Step 1: create TcpClient and connect to server 87 client = new TcpClient(); 88 client.Connect( "localhost", 5000 ); 89 90 // Step 2: get NetworkStream associated with TcpClient 91 output = client.GetStream(); 92 93 // create objects for writing and reading across stream 94 writer = new BinaryWriter( output ); 95 reader = new BinaryReader( output ); 96 Client.cs
Loop until client receive connection-terminate message To obtain next message from the server 97 displayTextBox.Text += "\r\nGot I/O streams\r\n"; 98 99 inputTextBox.ReadOnly = false; 100 101 // loop until server signals termination 102 do 103 { 104 105 // Step 3: processing phase 106 try 107 { 108 // read message from server 109 message = reader.ReadString(); 110 displayTextBox.Text += "\r\n" + message; 111 } 112 113 // handle exception if error in reading server data 114 catch ( Exception ) 115 { 116 System.Environment.Exit( 117 System.Environment.ExitCode ); 118 } 119 } while( message != "SERVER>>> TERMINATE" ); 120 121 displayTextBox.Text += "\r\nClosing connection.\r\n"; 122 123 // Step 4: close connection 124 writer.Close(); 125 reader.Close(); 126 output.Close(); 127 client.Close(); 128 Application.Exit(); 129 } 130 Client.cs
131 // handle exception if error in establishing connection 132 catch ( Exception error ) 133 { 134 MessageBox.Show( error.ToString() ); 135 } 136 137 } // end method RunClient 138 139 } // end class Client Client.cs
22.5 Connectionless Client/Server Interaction with Datagram • Resembles postal services • Bundles and sends information in packets
Creates an instance of UdpClient class to receive data at port 5000 Instance of class IPEndPoint to hold IP address and port number of client IPAddress object Port number of the endpoint 1 // Fig. 22.3: Server.cs 2 // Set up a Server that will receive packets from a 3 // client and send packets to a client. 4 5 using System; 6 using System.Drawing; 7 using System.Collections; 8 using System.ComponentModel; 9 using System.Windows.Forms; 10 using System.Data; 11 using System.Net; 12 using System.Net.Sockets; 13 using System.Threading; 14 15 // create the UDP server 16 public class Server : System.Windows.Forms.Form 17 { 18 private System.Windows.Forms.TextBox displayTextBox; 19 private UdpClient client; 20 private IPEndPoint receivePoint; 21 private System.ComponentModel.Container components = null; 22 23 // no-argument constructor 24 public Server() 25 { 26 InitializeComponent(); 27 28 client = new UdpClient( 5000 ); 29 receivePoint = new IPEndPoint( new IPAddress( 0 ), 0 ); 30 Thread readThread = new Thread( 31 new ThreadStart( WaitForPackets ) ); 32 Server.cs
Infinite loop wait for data to arrive at the Server Method Receive gets a byte array from the client Update Server’s display to include packet’s information and content 33 readThread.Start(); 34 } 35 36 // Visual Studio .NET generated code 37 38 [STAThread] 39 static void Main() 40 { 41 Application.Run( new Server() ); 42 } 43 44 // shut down the server 45 protected void Server_Closing( 46 object sender, CancelEventArgs e ) 47 { 48 System.Environment.Exit( System.Environment.ExitCode ); 49 } 50 51 // wait for a packet to arrive 52 public void WaitForPackets() 53 { 54 while ( true ) 55 { 56 // receive byte array from client 57 byte[] data = client.Receive( ref receivePoint ); 58 59 // output packet data to TextBox 60 displayTextBox.Text += "\r\nPacket received:" + 61 "\r\nLength: " + data.Length + "\r\nContaining: " + 62 System.Text.Encoding.ASCII.GetString( data ); 63 Server.cs
Method Send takes three argument IPEndPoint to send the data recievePoint store IP address and port number of sender Echo data back to the client The byte array to send The array’s length 64 displayTextBox.Text += 65 "\r\n\r\nEcho data back to client..."; 66 67 // echo information from packet back to client 68 client.Send( data, data.Length, receivePoint ); 69 displayTextBox.Text += "\r\nPacket sent\r\n"; 70 } 71 72 } // end method WaitForPackets 73 74 } // end class Server Server.cs
1 // Fig. 22.4: Client.cs 2 // Set up a Client that sends packets to a server and receives 3 // packets from a server. 4 5 using System; 6 using System.Drawing; 7 using System.Collections; 8 using System.ComponentModel; 9 using System.Windows.Forms; 10 using System.Data; 11 using System.Net; 12 using System.Net.Sockets; 13 using System.Threading; 14 15 // run the UDP client 16 public class Client : System.Windows.Forms.Form 17 { 18 private System.Windows.Forms.TextBox inputTextBox; 19 private System.Windows.Forms.TextBox displayTextBox; 20 21 private UdpClient client; 22 private IPEndPoint receivePoint; 23 24 private System.ComponentModel.Container components = null; 25 26 // no-argument constructor 27 public Client() 28 { 29 InitializeComponent(); 30 Client.cs
Instantiate a UdpClient object with port 5001 31 receivePoint = new IPEndPoint( new IPAddress( 0 ), 0 ); 32 client = new UdpClient( 5001 ); 33 Thread thread = 34 new Thread( new ThreadStart( WaitForPackets ) ); 35 thread.Start(); 36 } 37 38 // Visual Studio.NET generated code 39 40 [STAThread] 41 static void Main() 42 { 43 Application.Run( new Client() ); 44 } 45 46 // shut down the client 47 protected void Client_Closing( 48 object sender, CancelEventArgs e ) 49 { 50 System.Environment.Exit( System.Environment.ExitCode ); 51 } 52 53 // send a packet 54 protected void inputTextBox_KeyDown( 55 object sender, KeyEventArgs e ) 56 { 57 if ( e.KeyCode == Keys.Enter ) 58 { 59 // create packet (datagram) as string 60 string packet = inputTextBox.Text; 61 displayTextBox.Text += 62 "\r\nSending packet containing: " + packet; 63 Client.cs
Convert the string that user entered in TextBox to a byte array UdpClient method Send to send byte array to the Server Port 5000 is the Server’s port Method WaitForPacket is run on a separate thread Infinite loop to wait for the packets Receive blocks until a packet is received 64 // convert packet to byte array 65 byte[] data = 66 System.Text.Encoding.ASCII.GetBytes( packet ); 67 68 // send packet to server on port 5000 69 client.Send( data, data.Length, "localhost", 5000 ); 70 displayTextBox.Text += "\r\nPacket sent\r\n"; 71 inputTextBox.Clear(); 72 } 73 } // end method inputTextBox_KeyDown 74 75 // wait for packets to arrive 76 public void WaitForPackets() 77 { 78 while ( true ) 79 { 80 // receive byte array from server 81 byte[] data = client.Receive( ref receivePoint ); 82 83 // output packet data to TextBox 84 displayTextBox.Text += "\r\nPacket received:" + 85 "\r\nLength: " + data.Length + "\r\nContaining: " + 86 System.Text.Encoding.ASCII.GetString( data ) + 87 "\r\n"; 88 } 89 90 } // end method WaitForPackets 91 92 } // end class Client Client.cs
The Client window after sending a packet to the server and receiving the packet back from the server The Client window before sending a packet to the server Client.cs Program Output
22.6 Client/Server Tic-Tac-Toe Using a Multithreaded Server • Game of tic-tac-toe • Implemented with stream sockets • First person to connect is player ‘X’
1 // Fig. 22.5: Server.cs 2 // This class maintains a game of Tic-Tac-Toe for two 3 // client applications. 4 5 using System; 6 using System.Drawing; 7 using System.Collections; 8 using System.ComponentModel; 9 using System.Windows.Forms; 10 using System.Data; 11 using System.Net.Sockets; 12 using System.Threading; 13 using System.IO; 14 15 // awaits connections from two clients and allows them to 16 // play tic-tac-toe against each other 17 public class Server : System.Windows.Forms.Form 18 { 19 private System.Windows.Forms.TextBox displayTextBox; 20 21 private byte[] board; 22 23 private Player[] players; 24 private Thread[] playerThreads; 25 26 private TcpListener listener; 27 private int currentPlayer; 28 private Thread getPlayers; 29 30 private System.ComponentModel.Container components = null; 31 32 internal bool disconnected = false; 33 Server.cs
Create array to store player’s moves Correspond to the first player, ‘X’ Server uses to accept connections so that current Thread does not block while awaiting players 34 // default constructor 35 public Server() 36 { 37 InitializeComponent(); 38 39 board = new byte[ 9 ]; 40 41 players = new Player[ 2 ]; 42 playerThreads = new Thread[ 2 ]; 43 currentPlayer = 0; 44 45 // accept connections on a different thread 46 getPlayers = new Thread( new ThreadStart( SetUp ) ); 47 getPlayers.Start(); 48 } 49 50 // Visual Studio .NET-generated code 51 52 [STAThread] 53 static void Main() 54 { 55 Application.Run( new Server() ); 56 } 57 58 protected void Server_Closing( 59 object sender, CancelEventArgs e ) 60 { 61 disconnected = true; 62 } 63 Server.cs
Create TcpListener to listen for request on port 5000 Instantiate Player object representing the player Thread that execute Run methods of Player object Server notifies Player of connection by setting Player’s threadSuspend variable to false 64 // accepts connections from 2 players 65 public void SetUp() 66 { 67 // set up Socket 68 listener = new TcpListener( 5000 ); 69 listener.Start(); 70 71 // accept first player and start a thread for him or her 72 players[ 0 ] = 73 new Player( listener.AcceptSocket(), this, 0 ); 74 playerThreads[ 0 ] = new Thread( 75 new ThreadStart( players[ 0 ].Run ) ); 76 playerThreads[ 0 ].Start(); 77 78 // accept second player and start a thread for him or her 79 players[ 1 ] = 80 new Player( listener.AcceptSocket(), this, 1 ); 81 playerThreads[ 1 ] = 82 new Thread( new ThreadStart( players[ 1 ].Run ) ); 83 playerThreads[ 1 ].Start(); 84 85 // let the first player know that the other player has 86 // connected 87 lock ( players[ 0 ] ) 88 { 89 players[ 0 ].threadSuspended = false; 90 Monitor.Pulse( players[ 0 ] ); 91 } 92 } // end method SetUp 93 94 // appends the argument to text in displayTextBox 95 public void Display( string message ) 96 { 97 displayTextBox.Text += message + "\r\n"; 98 } Server.cs
lock statement ensure that only one move could be made Method will send to client message indicating whether the move was valid Place mark on the local representation of the board Notify that a move has been made Return false if location already contain a mark 99 100 // determine if a move is valid 101 public bool ValidMove( int location, int player ) 102 { 103 // prevent another thread from making a move 104 lock ( this ) 105 { 106 // while it is not the current player's turn, wait 107 while ( player != currentPlayer ) 108 Monitor.Wait( this ); 109 110 // if the desired square is not occupied 111 if ( !IsOccupied( location ) ) 112 { 113 // set the board to contain the current player's mark 114 board[ location ] = ( byte ) ( currentPlayer == 0 ? 115 'X' : 'O' ); 116 117 // set the currentPlayer to be the other player 118 currentPlayer = ( currentPlayer + 1 ) % 2; 119 120 // notify the other player of the move 121 players[ currentPlayer ].OtherPlayerMoved( location ); 122 123 // alert the other player it's time to move 124 Monitor.Pulse( this ); 125 126 return true; 127 } 128 else 129 return false; 130 } 131 } // end method ValidMove 132 Server.cs
Reference to the Socket object Contain the mark used by the player Player constructor Reference to Server object 133 // determines whether the specified square is occupied 134 public bool IsOccupied( int location ) 135 { 136 if ( board[ location ] == 'X' || board[ location ] == 'O' ) 137 return true; 138 else 139 return false; 140 } 141 142 // determines if the game is over 143 public bool GameOver() 144 { 145 // place code here to test for a winner of the game 146 return false; 147 } 148 149 } // end class Server 150 151 public class Player 152 { 153 internal Socket connection; 154 private NetworkStream socketStream; 155 private Server server; 156 private BinaryWriter writer; 157 private BinaryReader reader; 158 159 private int number; 160 private char mark; 161 internal bool threadSuspended = true; 162 163 // constructor requiring Socket, Server and int objects 164 // as arguments 165 public Player( Socket socket, Server serverValue, int newNumber ) 166 { Server.cs
Server calls method Run after instantiating a Player object Notify that the connection was successful 167 mark = ( newNumber == 0 ? 'X' : 'O' ); 168 169 connection = socket; 170 171 server = serverValue; 172 number = newNumber; 173 174 // create NetworkStream object for Socket 175 socketStream = new NetworkStream( connection ); 176 177 // create Streams for reading/writing bytes 178 writer = new BinaryWriter( socketStream ); 179 reader = new BinaryReader( socketStream ); 180 181 } // end constructor 182 183 // signal other player of move 184 public void OtherPlayerMoved( int location ) 185 { 186 // signal that opponent moved 187 writer.Write( "Opponent moved" ); 188 writer.Write( location ); // send location of move 189 } 190 191 // allows the players to make moves and receives moves 192 // from other player 193 public void Run() 194 { 195 bool done = false; 196 197 // display on the server that a connection was made 198 server.Display( "Player " + ( number == 0 ? 'X' : 'O' ) 199 + " connected" ); 200 Server.cs
Must wait for second player to join Report which char client will be placing on the board When threadSuspended becomes false, Player exits while loop Suspend thread for player ‘X’ until player ‘O’ is connected Enable user to play the game Run loop until Socket property Available indicates information from Socket If no information, thread goes to sleep Check whether server variable is true If true, Thread exits the method 201 // send the current player's mark to the server 202 writer.Write( mark ); 203 204 // if number equals 0 then this player is X, so send 205 writer.Write( "Player " + ( number == 0 ? 206 "X connected\r\n" : "O connected, please wait\r\n" ) ); 207 208 // wait for another player to arrive 209 if ( mark == 'X' ) 210 { 211 writer.Write( "Waiting for another player" ); 212 213 // wait for notification from server that another 214 // player has connected 215 lock ( this ) 216 { 217 while ( threadSuspended ) 218 Monitor.Wait( this ); 219 } 220 221 writer.Write( "Other player connected. Your move" ); 222 223 } // end if 224 225 // play game 226 while ( !done ) 227 { 228 // wait for data to become available 229 while ( connection.Available == 0 ) 230 { 231 Thread.Sleep( 1000 ); 232 233 if ( server.disconnected ) 234 return; 235 } Server.cs
To read int containing location user wants to place a mark Passes the int to Server method ValidMove If valid, then place the mark 236 237 // receive data 238 int location = reader.ReadInt32(); 239 240 // if the move is valid, display the move on the 241 // server and signal the move is valid 242 if ( server.ValidMove( location, number ) ) 243 { 244 server.Display( "loc: " + location ); 245 writer.Write( "Valid move." ); 246 } 247 248 // signal the move is invalid 249 else 250 writer.Write( "Invalid move, try again" ); 251 252 // if game is over, set done to true to exit while loop 253 if ( server.GameOver() ) 254 done = true; 255 256 } // end while loop 257 258 // close the socket connection 259 writer.Close(); 260 reader.Close(); 261 socketStream.Close(); 262 connection.Close(); 263 264 } // end method Run 265 266 } // end class Player Server.cs
Board created out of nine Square objects 1 // Fig. 22.6: Client.cs 2 // Client for the TicTacToe program. 3 4 using System; 5 using System.Drawing; 6 using System.Collections; 7 using System.ComponentModel; 8 using System.Windows.Forms; 9 using System.Data; 10 using System.Net.Sockets; 11 using System.Threading; 12 using System.IO; 13 14 // represents a tic-tac-toe player 15 public class Client : System.Windows.Forms.Form 16 { 17 private System.Windows.Forms.Label idLabel; 18 19 private System.Windows.Forms.TextBox displayTextBox; 20 21 private System.Windows.Forms.Panel panel1; 22 private System.Windows.Forms.Panel panel2; 23 private System.Windows.Forms.Panel panel3; 24 private System.Windows.Forms.Panel panel5; 25 private System.Windows.Forms.Panel panel6; 26 private System.Windows.Forms.Panel panel4; 27 private System.Windows.Forms.Panel panel7; 28 private System.Windows.Forms.Panel panel8; 29 private System.Windows.Forms.Panel panel9; 30 31 private Square[ , ] board; 32 private Square currentSquare; 33 34 private Thread outputThread; 35 Client.cs
36 private TcpClient connection; 37 private NetworkStream stream; 38 private BinaryWriter writer; 39 private BinaryReader reader; 40 41 private char myMark; 42 private bool myTurn; 43 44 private SolidBrush brush; 45 private System.ComponentModel.Container components = null; 46 47 bool done = false; 48 49 // default constructor 50 public Client() 51 { 52 InitializeComponent(); 53 54 board = new Square[ 3, 3 ]; 55 56 // create 9 Square objects and place them on the board 57 board[ 0, 0 ] = new Square( panel1, ' ', 0 ); 58 board[ 0, 1 ] = new Square( panel2, ' ', 1 ); 59 board[ 0, 2 ] = new Square( panel3, ' ', 2 ); 60 board[ 1, 0 ] = new Square( panel4, ' ', 3 ); 61 board[ 1, 1 ] = new Square( panel5, ' ', 4 ); 62 board[ 1, 2 ] = new Square( panel6, ' ', 5 ); 63 board[ 2, 0 ] = new Square( panel7, ' ', 6 ); 64 board[ 2, 1 ] = new Square( panel8, ' ', 7 ); 65 board[ 2, 2 ] = new Square( panel9, ' ', 8 ); 66 67 // create a SolidBrush for writing on the Squares 68 brush = new SolidBrush( Color.Black ); 69 Client.cs
Open connection to server Obtain reference to the connection’s associated NetworkStream object Thread to read messages sent from the server to the client 70 // Make connection to sever and get the associated 71 // network stream. Start separate thread to allow this 72 // program to continually update its output in textbox. 73 connection = new TcpClient( "localhost", 5000 ); 74 stream = connection.GetStream(); 75 76 writer = new BinaryWriter( stream ); 77 reader = new BinaryReader( stream ); 78 79 // start a new thread for sending and receiving messages 80 outputThread = new Thread( new ThreadStart( Run ) ); 81 outputThread.Start(); 82 } // end Client constructor 83 84 // Visual Studio .NET-generated code 85 86 [STAThread] 87 static void Main() 88 { 89 Application.Run( new Client() ); 90 } 91 92 protected void Client_Paint ( 93 object sender, System.Windows.Forms.PaintEventArgs e ) 94 { 95 PaintSquares(); 96 } 97 98 protected void Client_Closing( 99 object sender, CancelEventArgs e ) 100 { 101 done = true; 102 } 103 Client.cs
104 // draws the mark of each square 105 public void PaintSquares() 106 { 107 Graphics g; 108 109 // draw the appropriate mark on each panel 110 for ( int row = 0; row < 3; row++ ) 111 for ( int column = 0; column < 3; column++ ) 112 { 113 // get the Graphics for each Panel 114 g = board[ row, column ].SquarePanel.CreateGraphics(); 115 116 // draw the appropriate letter on the panel 117 g.DrawString( board[ row, column ].Mark.ToString(), 118 this.Font, brush, 8, 8 ); 119 } 120 } // end method PaintSquares 121 122 // send location of the clicked square to server 123 protected void square_MouseUp( 124 object sender, System.Windows.Forms.MouseEventArgs e ) 125 { 126 // for each square check if that square was clicked 127 for ( int row = 0; row < 3; row++ ) 128 for ( int column = 0; column < 3; column++ ) 129 if ( board[ row, column ].SquarePanel == sender ) 130 { 131 CurrentSquare = board[ row, column ]; 132 133 // send the move to the server 134 SendClickedSquare( board[ row, column ].Location ); 135 } 136 } // end method square_MouseUp 137 Client.cs
If message indicate move to be valid, client sets mark on current square 138 // control thread that allows continuous update of the 139 // textbox display 140 public void Run() 141 { 142 // first get players's mark (X or O) 143 myMark = reader.ReadChar(); 144 idLabel.Text = "You are player \"" + myMark + "\""; 145 myTurn = ( myMark == 'X' ? true : false ); 146 147 // process incoming messages 148 try 149 { 150 // receive messages sent to client 151 while ( true ) 152 ProcessMessage( reader.ReadString() ); 153 } 154 catch ( EndOfStreamException ) 155 { 156 MessageBox.Show( "Server is down, game over", "Error", 157 MessageBoxButtons.OK, MessageBoxIcon.Error ); 158 } 159 160 } // end method Run 161 162 // process messages sent to client 163 public void ProcessMessage( string message ) 164 { 165 // if the move player sent to the server is valid 166 // update the display, set that square's mark to be 167 // the mark of the current player and repaint the board 168 if ( message == "Valid move." ) 169 { 170 displayTextBox.Text += 171 "Valid move, please wait.\r\n"; Client.cs
Repaint the square to accommodate the changes Move invalid, tell user to pick another one Indicate opponent made a move Read from server an int specifying location 172 currentSquare.Mark = myMark; 173 PaintSquares(); 174 } 175 176 // if the move is invalid, display that and it is now 177 // this player's turn again 178 else if ( message == "Invalid move, try again" ) 179 { 180 displayTextBox.Text += message + "\r\n"; 181 myTurn = true; 182 } 183 184 // if opponent moved 185 else if ( message == "Opponent moved" ) 186 { 187 // find location of their move 188 int location = reader.ReadInt32(); 189 190 // set that square to have the opponents mark and 191 // repaint the board 192 board[ location / 3, location % 3 ].Mark = 193 ( myMark == 'X' ? 'O' : 'X' ); 194 PaintSquares(); 195 196 displayTextBox.Text += 197 "Opponent moved. Your turn.\r\n"; 198 199 // it is now this player's turn 200 myTurn = true; 201 } 202 Client.cs
203 // display the message 204 else 205 displayTextBox.Text += message + "\r\n"; 206 207 } // end method ProcessMessage 208 209 // sends the server the number of the clicked square 210 public void SendClickedSquare( int location ) 211 { 212 // if it is the current player's move right now 213 if ( myTurn ) 214 { 215 // send the location of the move to the server 216 writer.Write( location ); 217 218 // it is now the other player's turn 219 myTurn = false; 220 } 221 } 222 223 // write-only property for the current square 224 public Square CurrentSquare 225 { 226 set 227 { 228 currentSquare = value; 229 } 230 } 231 232 } // end class Client Client.cs
Client.cs Program Output Server output after(1.) Server output after (2.) Server output after (3.) Server output after (4.)
1 // Fig. 22.7: Square.cs 2 // A Square on the TicTacToe board. 3 4 using System.Windows.Forms; 5 6 // the representation of a square in a tic-tac-toe grid 7 public class Square 8 { 9 private Panel panel; 10 privatechar mark; 11 private int location; 12 13 // constructor 14 public Square( Panel newPanel, char newMark, int newLocation ) 15 { 16 panel = newPanel; 17 mark = newMark; 18 location = newLocation; 19 } 20 21 // property SquarePanel; the panel which the square represents 22 public Panel SquarePanel 23 { 24 get 25 { 26 return panel; 27 } 28 } // end property SquarePanel 29 Square.cs
30 // property Mark; the mark of the square 31 public char Mark 32 { 33 get 34 { 35 return mark; 36 } 37 38 set 39 { 40 mark = value; 41 } 42 } // end property Mark 43 44 // property Location; the square's location on the board 45 public int Location 46 { 47 get 48 { 49 return location; 50 } 51 } // property Location 52 53 } // end class Square Square.cs