Chapter 23

1
23
Networking:
Streams-Based
Sockets and
Datagrams
 2006 Pearson Education, Inc. All rights reserved.
2
OBJECTIVES
In this chapter you will learn:
 To implement networking applications that use
sockets and datagrams.
 To implement clients and servers that communicate
with one another.
 To implement network-based collaborative
applications.
 To construct a multithreaded server.
 To use the WebBrowser control to add Web
browsing capabilities to any application.
 To use .NET remoting to enable an application
executing on one computer to invoke methods from
an application executing on a different computer.
 2006 Pearson Education, Inc. All rights reserved.
3
23.1
Introduction
23.2
Connection-Oriented vs. Connectionless Communication
23.3
Protocols for Transporting Data
23.4
Establishing a Simple TCP Server (Using Stream Sockets)
23.5
Establishing a Simple TCP Client (Using Stream Sockets)
23.6
Client/Server Interaction with Stream-Socket Connections
23.7
Connectionless Client/Server Interaction with Datagrams
23.8
Client/Server Tic-Tac-Toe Using a Multithreaded Server
23.9
WebBrowser
Control
23.10 .NET Remoting
23.11 Wrap-Up
 2006 Pearson Education, Inc. All rights reserved.
4
23.1 Introduction
• The .NET FCL provides a number of built-in networking
capabilities
- Makes it easy to develop Internet- and Web-based
applications
• Provide overview of the communication techniques and
technologies used to transmit data over the Internet
• Discuss basic concepts of establishing a connection
between two applications using streams of data
- Enables programs to communicate with one another as
easily as writing to and reading from files on disk
• Discuss connectionless techniques for transmitting data
between applications that is less reliable but much more
efficient
 2006 Pearson Education, Inc. All rights reserved.
5
23.2 Connection-Oriented vs.
Connectionless Communication
• Two primary approaches to communicating between
applications
- Connection oriented communications
• Similar to the telephone system
- A connection is established and held for the length of the session
• Handshaking
- Computers send each other control information
• Through a technique called initiate an end-to-end connection
• Data is sent in packets
- Contain pieces of the data along with information that helps the
Internet route the packets to the proper destination
• Ensures reliable communications on unreliable networks
- Guarantee that sent packets will arrive at the intended receiver
undamaged and be reassembled in the correct sequence
• The Internet does not guarantee anything about the packets sent
 2006 Pearson Education, Inc. All rights reserved.
6
23.2 Connection-Oriented vs.
Connectionless Communication (Cont.)
- Connectionless communications
• Similar to the postal service:
- Two letters mailed from the same place and to the same
destination may take two dramatically different paths
through the system and even arrive at different times, or
not at all
• The two computers do not handshake before transmission
- Reliability is not guaranteed
• Data sent may never reach the intended recipient
• Avoids the overhead associated with handshaking and
enforcing reliability
- Less information often needs to be passed between the
hosts
 2006 Pearson Education, Inc. All rights reserved.
7
23.3 Protocols for Transporting Data
• Protocols
- Sets of rules that govern how two entities should
interact
- Networking capabilities are defined in the
System.Net.Sockets namespace
• Transmission Control Protocol (TCP)
• User Datagram Protocol (UDP)
- TCP
• A connection-oriented communication protocol which guarantees
that sent packets will arrive at the intended receiver undamaged
and in the correct sequence
- If packets are lost, TCP ensures that the packets are sent again
- If the packets arrive out of order, TCP reassembles them in the
correct order transparently to the receiving application
- If duplicate packets arrive, TCP discards them
• Send information across a network as simply and reliably as writing
to a file on a local computer
 2006 Pearson Education, Inc. All rights reserved.
8
23.3 Protocols for Transporting Data
(Cont.)
- UDP
• Incurs the minimum overhead necessary to communicate
between applications
- Do not need to carry the information that TCP packets
carry to ensure reliability
- Reduces network traffic relative to TCP due to the
absence of handshaking, retransmissions, etc
• Makes no guarantees that packets, called datagrams, will
reach their destination or arrive in their original order
 2006 Pearson Education, Inc. All rights reserved.
9
23.4 Establishing a Simple TCP Client
(Using Stream Sockets)
• Typically with TCP, a server waits for a
connection request
- Contains a control statement or block of code that executes
until the server receives the request
- On receiving a request, the server establishes a connection
to the client
•Socket object
- Manages the connection between server and client
 2006 Pearson Education, Inc. All rights reserved.
10
23.4 Establishing a Simple TCP Client
(Using Stream Sockets) (Cont.)
• Establish a simple server with TCP and stream sockets requires 5 steps
(Uses namespace System.Net.Sockets)
- Step 1: Create an object of class TcpListener of namespace
• Using an IP Address and port number
- Step 2: Call TcpListener’s Start method
• Causes the TcpListener object to begin listening for connection requests
• An object of class Socket manages a connection to client
• Method AcceptSocket of class TcpListener accepts a connection request
- Step 3: Establishes the streams used for communication with the
client
• Create a NetworkStream object that uses the Socket object
- Represent the connection to perform the sending and receiving of data
- Step 4: The server and client communicate using the connection
established in the third step
- Step 5: Terminate connections
• Server calls method Close of the BinaryReader, BinaryWriter,
NetworkStream and Socket to terminate the connection
 2006 Pearson Education, Inc. All rights reserved.
11
Software Engineering Observation 23.1
Port numbers can have values between 0 and
65535. Many operating systems reserve port
numbers below 1024 for system services (such
as e-mail and Web servers). Applications must
be granted special privileges to use these
reserved port numbers.
 2006 Pearson Education, Inc. All rights reserved.
12
Software Engineering Observation 23.2
Multithreaded servers can efficiently manage
simultaneous connections with multiple
clients. This architecture is precisely what
popular UNIX and Windows network servers
use.
 2006 Pearson Education, Inc. All rights reserved.
13
Software Engineering Observation 23.3
A multithreaded server can be implemented to
create a thread that manages network I/O
across a Socket object returned by method
AcceptSocket. A multithreaded server also
can be implemented to maintain a pool of
threads that manage network I/O across newly
created Sockets.
 2006 Pearson Education, Inc. All rights reserved.
14
Performance Tip 23.1
In high-performance systems with abundant
memory, a multithreaded server can be
implemented to create a pool of threads. These
threads can be assigned quickly to handle
network I/O across multiple Sockets. Thus,
when a connection is received, the server does
not incur the overhead of thread creation.
 2006 Pearson Education, Inc. All rights reserved.
15
23.5 Establishing a Simple TCP Client
(Using Stream Sockets)
• There are 4 steps to creating a simple TCP client:
- Step 1: Create an object of class TcpClient and connect to the server using
method Connect
• If the connection is successful, returns a positive integer
-
Otherwise, it returns 0
- Step 2: The TcpClient uses its GetStream method to get a
NetworkStream so that it can write to and read from the server
• Use the NetworkStream object to create a BinaryWriter and a
BinaryReader that will be used to send information to and receive information
from the server
- Step 3: The client and the server communicate
- Step 4: Require the client to close the connection by calling method Close
• For BinaryReader, BinaryWriter, NetworkStream and TcpClient
 2006 Pearson Education, Inc. All rights reserved.
16
23.6 Client/Server Interaction with
Stream-Socket Connections
• Windows Form controls are not thread safe
- A control that is modified from multiple threads is not
guaranteed to be modified correctly
• The Visual Studio 2005 Documentation
recommends that only the thread which created
the GUI should modify the controls
- Class Control’s method Invoke to help ensure this
• Localhost
- A.K.A. the loopback IP address
- Equivalent to the IP address 127.0.0.1
 2006 Pearson Education, Inc. All rights reserved.
1
2
// Fig. 23.1: ChatServer.cs
// Set up a server that will receive a connection from a client, send a
3
// string to the client, chat with the client and close the connection.
4
5
6
using System;
using System.Windows.Forms;
using System.Threading;
7
8
using System.Net;
using System.Net.Sockets;
Using namespaces for
networking capabilities
13
14
public ChatServerForm()
{
15
16
InitializeComponent();
} // end constructor
Outline
ChatServer.cs
(1 of 7)
9 using System.IO;
10
11 public partial class ChatServerForm : Form
12 {
17
Create private instance
variables for
networking purposes
17
18
19
private Socket connection; // Socket for accepting a connection
private Thread readThread; // Thread for processing incoming messages
20
private NetworkStream socketStream; // network data stream
21
22
private BinaryWriter writer; // facilitates writing to the stream
private BinaryReader reader; // facilitates reading from the stream
23
24
// initialize thread for reading
25
private void ChatServerForm_Load( object sender, EventArgs e )
26
{
27
28
29
readThread = new Thread( new ThreadStart( RunServer ) );
readThread.Start();
} // end method CharServerForm_Load
Create a Thread that
will accept connections
from clients
Starts the Thread
 2006 Pearson Education,
Inc. All rights reserved.
30
18
31
// close all threads associated with this application
32
private void ChatServerForm_FormClosing( object sender,
33
34
35
Outline
FormClosingEventArgs e )
Terminate program and
close its threads
{
System.Environment.Exit( System.Environment.ExitCode );
36
37
} // end method CharServerForm_FormClosing
ChatServer.cs
38
39
// delegate that allows method DisplayMessage to be called
// in the thread that creates and maintains the GUI
(2 of 7)
40
private delegate void DisplayDelegate( string message );
41
42
43
// method DisplayMessage sets displayTextBox's Text property
// in a thread-safe manner
44
45
46
private void DisplayMessage( string message )
{
// if modifying displayTextBox is not thread safe
Represents methods that take
a string argument and
do not return a value
Returns true if the current thread is not
allowed to modify this control directly
47
48
49
50
if ( displayTextBox.InvokeRequired )
{
// use inherited method Invoke to execute DisplayMessage
// via a delegate
51
52
53
Invoke( new DisplayDelegate( DisplayMessage ),
new object[] { message } );
} // end if
54
55
56
Pass a new DisplayDelegate
representing the method
DisplayMessage and a
new object array consisting of
the argument message
else // OK to modify displayTextBox in current thread
displayTextBox.Text += message;
} // end method DisplayMessage
Appends message to
displayTextBox
 2006 Pearson Education,
Inc. All rights reserved.
57
19
58
// delegate that allows method DisableInput to be called
59
// in the thread that creates and maintains the GUI
60
61
private delegate void DisableInputDelegate( bool value );
62
// method DisableInput sets inputTextBox's ReadOnly property
63
// in a thread-safe manner
64
private void DisableInput( bool value )
65
{
66
// if modifying inputTextBox is not thread safe
67
if ( inputTextBox.InvokeRequired )
68
{
Outline
Delegate for
DisableInput
ChatServer.cs
Returns true if the current thread is not
(3 of 7)
allowed to modify this control directly
69
70
// use inherited method Invoke to execute DisableInput
// via a delegate
71
Invoke( new DisableInputDelegate( DisableInput ),
72
73
74
75
76
new object[] { value } );
} // end if
else // OK to modify inputTextBox in current thread
Pass a new
DisableInputDelegate
representing the method
DisableInput and a new
object array consisting of the
argument value
inputTextBox.ReadOnly = value;
} // end method DisableInput
Set inputTextBox.ReadOnly to the
value of the boolean argument
 2006 Pearson Education,
Inc. All rights reserved.
77
78
// send the text typed at the server to the client
79
private void inputTextBox_KeyDown( object sender, KeyEventArgs e )
80
81
82
{
83
84
85
86
87
20
// send the text to the client
try
ChatServer.cs
{
if ( e.KeyCode == Keys.Enter && inputTextBox.ReadOnly == false )
{
writer.Write( "SERVER>>> " + inputTextBox.Text );
displayTextBox.Text += "\r\nSERVER>>> " + inputTextBox.Text;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
Outline
// if the user at the server signaled termination
// sever the connection to the client
if ( inputTextBox.Text == "TERMINATE" )
connection.Close();
inputTextBox.Clear(); // clear the user’s input
(4 ofmessage
7)
Sends
via
method Write of class
BinaryWriter
Calls method Close of
the Socket object to
close the connection
} // end if
} // end try
catch ( SocketException )
{
displayTextBox.Text += "\nError writing object";
} // end catch
} // end method inputTextBox_KeyDown
 2006 Pearson Education,
Inc. All rights reserved.
102
21
103
// allows a client to connect; displays text the client sends
104
public void RunServer()
105
106
{
107
TcpListener listener;
Create instance of TcpListener
int counter = 1;
ChatServer.cs
108
109
// wait for a client connection and display the text
110
111
// that the client sends
try
112
{
(5 of 7)
113
114
115
// Step 1: create TcpListener
IPAddress local = IPAddress.Parse( "127.0.0.1" );
listener = new TcpListener( local, 50000 );
116
117
118
119
// Step 2: TcpListener waits for connection request
listener.Start();
120
121
122
123
124
125
126
127
128
129
Outline
Instantiate the TcpListener object
to listen for a connection request
from a client at port 50000
Causes the TcpListener to
begin waiting for request
// Step 3: establish connection upon client request
while ( true )
{
DisplayMessage( "Waiting for connection\r\n" );
// accept an incoming connection
connection = listener.AcceptSocket();
Calls method AcceptSocket
of the TcpListener object,
which returns a Socket
upon successful connection
// create NetworkStream object associated with socket
socketStream = new NetworkStream( connection );
Passes the Socket object as an
argument to the constructor of
a NetworkStream object
 2006 Pearson Education,
Inc. All rights reserved.
130
22
131
// create objects for transferring data across stream
132
133
writer = new BinaryWriter( socketStream );
reader = new BinaryReader( socketStream );
134
Create instances ofOutline
BinaryWriter
and BinaryReader classes for
writing and reading data
135
136
DisplayMessage( "Connection " + counter + " received.\r\n" );
137
// inform client that connection was successfull
138
writer.Write( "SERVER>>> Connection successful" );
ChatServer.cs
139
140
141
DisableInput( false ); // enable inputTextBox
142
143
string theReply = "";
144
// Step 4: read string data sent from client
145
146
147
do
148
149
Read a string from the stream
{
try
{
// read the string sent to the server
150
theReply = reader.ReadString();
151
152
// display the message
153
154
(6 of 7)
Send to the client
a string
notifying the user of a
successful connection
DisplayMessage( "\r\n" + theReply );
} // end try
 2006 Pearson Education,
Inc. All rights reserved.
155
catch ( Exception )
156
157
{
158
159
break;
} // end catch
23
// handle exception if error reading data
} while ( theReply != "CLIENT>>> TERMINATE"
connection.Connected );
160
161
Outline
&&
ChatServer.cs
162
163
DisplayMessage( "\r\nUser terminated connection\r\n" );
164
165
// Step 5: close connection
166
167
168
169
writer.Close();
reader.Close();
socketStream.Close();
connection.Close();
(7 of 7)
Release program’s resources
by closing its connections
170
DisableInput( true ); // disable InputTextBox
171
counter++;
} // end while
172
173
174
} // end try
175
catch ( Exception error )
176
177
{
178
} // end catch
179
MessageBox.Show( error.ToString() );
} // end method RunServer
180 } // end class ChatServerForm
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 23.2: ChatClient.cs
2
// Set up a client that will send information to and
3
// read information from a server.
4
using System;
5
using System.Windows.Forms;
6
using System.Threading;
7
using System.Net.Sockets;
8
using System.IO;
24
Outline
Using namespaces for
networking capabilities
ChatClient.cs
(1 of 9)
9
10 public partial class ChatClientForm : Form
11 {
12
public ChatClientForm()
13
{
InitializeComponent();
14
15
} // end constructor
Create private instance
variables for
networking purposes
16
17
private NetworkStream output; // stream for receiving data
18
private BinaryWriter writer; // facilitates writing to the stream
19
private BinaryReader reader; // facilitates reading from the stream
20
private Thread readThread; // Thread for processing incoming messages
21
private string message = "";
22
23
// initialize thread for reading
24
private void ChatClientForm_Load( object sender, EventArgs e )
25
{
26
readThread = new Thread( new ThreadStart( RunClient ) );
27
readThread.Start();
28
Create a Thread to
handle all incoming
messages
Starts the Thread
} // end method ChatClientForm_Load
 2006 Pearson Education,
Inc. All rights reserved.
29
25
30
// close all threads associated with this application
31
private void ChatClientForm_FormClosing( object sender,
34
35
Terminate program and
close its threads
FormClosingEventArgs e )
32
33
Outline
{
System.Environment.Exit( System.Environment.ExitCode );
ChatClient.cs
} // end method ChatClientForm_FormClosing
36
37
// delegate that allows method DisplayMessage to be called
38
// in the thread that creates and maintains the GUI
39
40
private delegate void DisplayDelegate( string message );
41
42
// method DisplayMessage sets displayTextBox's Text property
// in a thread-safe manner
43
44
private void DisplayMessage( string message )
{
Returns true if the current thread is not
allowed to modify this control directly
45
46
// if modifying displayTextBox is not thread safe
if ( displayTextBox.InvokeRequired )
47
48
{
49
50
// use inherited method Invoke to execute DisplayMessage
// via a delegate
Invoke( new DisplayDelegate( DisplayMessage ),
51
52
new object[] { message } );
} // end if
53
else // OK to modify displayTextBox in current thread
54
55
(2 of 9)
Represents methods that take
a string argument and
do not return a value
Pass a new DisplayDelegate
representing the method
DisplayMessage and a
new object array consisting of
the argument message
displayTextBox.Text += message;
} // end method DisplayMessage
Appends message to
displayTextBox
 2006 Pearson Education,
Inc. All rights reserved.
56
26
57
// delegate that allows method DisableInput to be called
58
// in the thread that creates and maintains the GUI
59
60
private delegate void DisableInputDelegate( bool value );
61
// method DisableInput sets inputTextBox's ReadOnly property
62
63
// in a thread-safe manner
private void DisableInput( bool value )
64
{
65
// if modifying inputTextBox is not thread safe
66
67
if ( inputTextBox.InvokeRequired )
{
Outline
Delegate for
DisableInput
ChatClient.cs
Returns true if the current thread is not
(3 of 9)
allowed to modify this control directly
68
69
// use inherited method Invoke to execute DisableInput
// via a delegate
70
Invoke( new DisableInputDelegate( DisableInput ),
71
72
73
74
75
new object[] { value } );
} // end if
else // OK to modify inputTextBox in current thread
Pass a new
DisableInputDelegate
representing the method
DisableInput and a new
object array consisting of the
argument value
inputTextBox.ReadOnly = value;
} // end method DisableInput
Set inputTextBox.ReadOnly to
the value of the boolean argument
 2006 Pearson Education,
Inc. All rights reserved.
76
27
77
// sends text the user typed to server
78
79
private void inputTextBox_KeyDown( object sender, KeyEventArgs e )
{
80
try
81
{
82
if ( e.KeyCode == Keys.Enter && inputTextBox.ReadOnly == false )
83
{
writer.Write( "CLIENT>>> " + inputTextBox.Text );
displayTextBox.Text += "\r\nCLIENT>>> " + inputTextBox.Text;
inputTextBox.Clear();
84
85
86
87
88
89
} // end if
} // end try
catch ( SocketException )
90
91
{
92
93
Outline
ChatClient.cs
(4 ofmessage
9)
Sends
via
method Write of class
BinaryWriter
displayTextBox.Text += "\nError writing object";
} // end catch
} // end method inputTextBox_KeyDown
 2006 Pearson Education,
Inc. All rights reserved.
94
95
// connect to server and display server-generated text
96
public void RunClient()
97
98
{
99
100
101
102
103
28
TcpClient client;
Outline
Create instance of TcpClient
ChatClient.cs
// instantiate TcpClient for sending data to server
try
{
(5 of 9)
DisplayMessage( "Attempting connection\r\n" );
104
105
106
// Step 1: create TcpClient and connect to server
client = new TcpClient();
107
108
109
110
client.Connect( "127.0.0.1", 50000 );
Instantiate the TcpClient, then
call its Connect method to
establish a connection
// Step 2: get NetworkStream associated with TcpClient
output = client.GetStream();
111
112
113
114
115
116
DisplayMessage( "\r\nGot I/O streams\r\n" );
117
DisableInput( false ); // enable inputTextBox
// create objects for writing and reading across stream
writer = new BinaryWriter( output );
reader = new BinaryReader( output );
Retrieve the NetworkStream
object that send data to and
receive data from the server
Create instances of BinaryWriter
and BinaryReader classes for
writing and reading data
 2006 Pearson Education,
Inc. All rights reserved.
118
29
119
120
// loop until server signals termination
do
121
122
{
123
124
Outline
// Step 3: processing phase
try
{
125
// read message from server
126
message = reader.ReadString();
ChatClient.cs
(6 of
Read and display
the9)
message
127
128
DisplayMessage( "\r\n" + message );
} // end try
129
130
131
132
catch ( Exception )
{
// handle exception if error in reading server data
System.Environment.Exit( System.Environment.ExitCode );
133
} // end catch
134
} while ( message != "SERVER>>> TERMINATE" );
135
136
// Step 4: close connection
137
writer.Close();
138
reader.Close();
139
140
output.Close();
client.Close();
Release program’s resources
by closing its connections
141
142
143
Application.Exit();
} // end try
 2006 Pearson Education,
Inc. All rights reserved.
144
145
146
147
catch ( Exception error )
{
// handle exception if error in establishing connection
MessageBox.Show( error.ToString(), "Connection Error",
Outline
MessageBoxButtons.OK, MessageBoxIcon.Error );
148
149
30
System.Environment.Exit( System.Environment.ExitCode );
ChatClient.cs
150
} // end catch
151
} // end method RunClient
152 } // end class ChatClientForm
(a)
(7 of 9)
(b)
 2006 Pearson Education,
Inc. All rights reserved.
31
Outline
(c)
(d)
ChatClient.cs
(8 of 9)
(e)
(f)
 2006 Pearson Education,
Inc. All rights reserved.
32
Outline
(g)
ChatClient.cs
(9 of 9)
 2006 Pearson Education,
Inc. All rights reserved.
33
23.7 Connectionless Client/Server
Interaction with Datagrams
• Connectionless transmission
- Bundles and sends information in packets called
datagrams
- Class UdpClient
• For connectionless transmission
• Methods Send and Receive
- Transmit data with Socket’s SendTo method
- Read data with Socket’s ReceiveFrom method
- Class IPEndPoint
• Hold the IP address and port number of the client(s)
 2006 Pearson Education, Inc. All rights reserved.
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
5
using System;
using System.Windows.Forms;
6
using System.Net;
7
8
using System.Net.Sockets;
using System.Threading;
9
10 public partial class PacketServerForm : Form
11 {
12
13
14
public PacketServerForm()
{
InitializeComponent();
15
16
17
18
} // end constructor
34
Outline
Using namespaces for
networking capabilities
PacketServer.cs
(1 of 3)
Create private instance variables
of class UdpClient and
IPEndPoint
Receives data at port 50000
private UdpClient client;
private IPEndPoint receivePoint;
19
20
21
22
23
// initialize variables and thread for receiving packets
private void PacketServerForm_Load( object sender, EventArgs e )
{
client = new UdpClient( 50000 );
24
25
26
27
28
receivePoint = new IPEndPoint( new IPAddress( 0 ), 0 );
Thread readThread =
new Thread( new ThreadStart( WaitForPackets ) );
readThread.Start();
} // end method PacketServerForm_Load
Hold the IP address and port
number of the clients that transit
to PacketServerForm
Create a Thread to
handle packages
Starts the Thread
 2006 Pearson Education,
Inc. All rights reserved.
29
35
30
// shut down the server
31
private void PacketServerForm_FormClosing( object sender,
FormClosingEventArgs e )
32
{
33
Outline
Terminate program and
close its threads
System.Environment.Exit( System.Environment.ExitCode );
34
} // end method PacketServerForm_FormClosing
PacketServer.cs
37
// delegate that allows method DisplayMessage to be called
(2 of 3)
38
// in the thread that creates and maintains the GUI
39
40
private delegate void DisplayDelegate( string message );
41
42
// method DisplayMessage sets displayTextBox's Text property
// in a thread-safe manner
43
44
private void DisplayMessage( string message )
35
36
{
45
46
// if modifying displayTextBox is not thread safe
if ( displayTextBox.InvokeRequired )
47
48
{
49
50
// use inherited method Invoke to execute DisplayMessage
// via a delegate
Invoke( new DisplayDelegate( DisplayMessage ),
51
52
new object[] { message } );
} // end if
53
else // OK to modify displayTextBox in current thread
54
55
displayTextBox.Text += message;
} // end method DisplayMessage
 2006 Pearson Education,
Inc. All rights reserved.
56
36
57
// wait for a packet to arrive
58
public void WaitForPackets()
59
60
61
{
62
63
64
while ( true )
{
Outline
Receives a byte array
from the client
// set up packet
byte[] data = client.Receive( ref receivePoint );
DisplayMessage( "\r\nPacket received:" +
65
"\r\nLength: " + data.Length +
66
"\r\nContaining: " +
67
68
69
System.Text.Encoding.ASCII.GetString( data ) );
PacketServer.cs
(3 of 3)
Return the string of
the byte array
// echo information from packet back to client
70
DisplayMessage( "\r\n\r\nEcho data back to client..." );
71
client.Send( data, data.Length, receivePoint );
72
DisplayMessage( "\r\nPacket sent\r\n" );
73
} // end while
74
} // end method WaitForPackets
75 } // end class PacketServerForm
Echos the data back to the
client using UdpClient’s
method Send
 2006 Pearson Education,
Inc. All rights reserved.
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
7
using System.Net;
using System.Net.Sockets;
8 using System.Threading;
9
10 public partial class PacketClientForm : Form
11 {
12
13
14
15
16
public PacketClientForm()
{
InitializeComponent();
} // end constructor
private UdpClient client;
private IPEndPoint receivePoint;
37
Outline
Using namespaces for
networking capabilities
(1 of 4)
Create private instance
variables of class UdpClient
and IPEndPoint
Hold the IP address and port
number of the clients that transit
to PacketClientForm
17
18
19
20
// initialize variables and thread for receiving packets
21
22
23
private void PacketClientForm_Load( object sender, EventArgs e )
{
receivePoint = new IPEndPoint( new IPAddress( 0 ), 0 );
24
25
26
27
28
client = new UdpClient( 50001 );
Thread thread =
new Thread( new ThreadStart( WaitForPackets ) );
thread.Start();
} // end method PacketClientForm_Load
PacketClient.cs
Receives data at port 50001
Create a Thread to
handle packages
Starts the Thread
 2006 Pearson Education,
Inc. All rights reserved.
29
38
30
// shut down the client
31
private void PacketClientForm_FormClosing( object sender,
FormClosingEventArgs e )
32
33
34
{
Outline
Terminate program and
close its threads
System.Environment.Exit( System.Environment.ExitCode );
} // end method PacketClientForm_FormClosing
PacketClient.cs
37
// delegate that allows method DisplayMessage to be called
(2 of 4)
38
// in the thread that creates and maintains the GUI
39
40
private delegate void DisplayDelegate( string message );
41
42
// method DisplayMessage sets displayTextBox's Text property
// in a thread-safe manner
43
44
private void DisplayMessage( string message )
{
35
36
45
46
// if modifying displayTextBox is not thread safe
if ( displayTextBox.InvokeRequired )
47
48
{
49
50
// use inherited method Invoke to execute DisplayMessage
// via a delegate
Invoke( new DisplayDelegate( DisplayMessage ),
51
52
new object[] { message } );
} // end if
53
else // OK to modify displayTextBox in current thread
54
55
displayTextBox.Text += message;
} // end method DisplayMessage
 2006 Pearson Education,
Inc. All rights reserved.
56
39
57
// send a packet
58
private void inputTextBox_KeyDown( object sender, KeyEventArgs e )
59
60
{
61
62
63
Outline
if ( e.KeyCode == Keys.Enter )
{
// create packet (datagram) as string
string packet = inputTextBox.Text;
PacketClient.cs
64
65
66
displayTextBox.Text +=
"\r\nSending packet containing: " + packet;
(3 of 4)
67
68
69
// convert packet to byte array
byte[] data = System.Text.Encoding.ASCII.GetBytes( packet );
70
71
// send packet to server on port 50000
client.Send( data, data.Length, "127.0.0.1", 50000 );
72
displayTextBox.Text += "\r\nPacket sent\r\n";
73
74
75
inputTextBox.Clear();
} // end if
} // end method inputTextBox_KeyDown
Converts the string that the
user entered to a byte array
Send the byte array to the
PacketServerForm that
is located on the localhost
 2006 Pearson Education,
Inc. All rights reserved.
76
77
// wait for packets to arrive
78
public void WaitForPackets()
79
{
40
80
while ( true )
81
82
83
{
Outline
Receives a byte array
from the server
// receive byte array from server
byte[] data = client.Receive( ref receivePoint );
(4 of 4)
84
85
// output packet data to TextBox
86
DisplayMessage( "\r\nPacket received:" +
87
88
89
PacketClient.cs
"\r\nLength: " + data.Length + "\r\nContaining: " +
System.Text.Encoding.ASCII.GetString( data ) + "\r\n" );
} // end while
90
} // end method WaitForPackets
91 } // end class PacketClientForm
(a) Packet Client window before sending a
packet to the server
Return the string of
the byte array
Display its contents
in the TextBox
(b) Packet Client window after sending a
packet to the server and receiving it back
 2006 Pearson Education,
Inc. All rights reserved.
41
23.8 Client/Server Tic-Tac-Toe Using a
Multithreaded Server
• Multithreaded servers can manage many
simultaneous connections with multiple clients
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 23.5: TicTacToeServer.cs
2
// This class maintains a game of Tic-Tac-Toe for two
3
4
// client applications.
using System;
5
using System.Windows.Forms;
6
7
8
9
using
using
using
using
System.Net;
System.Net.Sockets;
System.Threading;
System.IO;
42
Outline
Using namespaces for
networking capabilities
TicTacToeServer.cs
(1 of 10)
10
11 public partial class TicTacToeServerForm : Form
12 {
Create instance variables for
implementing the server side of the
Tic-Tac-Toe networking game
13
public TicTacToeServerForm()
14
15
16
17
{
18
private byte[] board; // the local representation of the game board
19
20
private Player[] players; // two Player objects
private Thread[] playerThreads; // Threads for client interaction
21
private TcpListener listener; // listen for client connection
22
23
24
private int currentPlayer; // keep track of whose turn it is
private Thread getPlayers; // Thread for acquiring client connections
internal bool disconnected = false; // true if the server closes
InitializeComponent();
} // end constructor
 2006 Pearson Education,
Inc. All rights reserved.
25
26
// initialize variables and thread for receiving clients
27
28
private void TicTacToeServerForm_Load( object sender, EventArgs e )
{
43
Store the moves the players have made
29
board = new byte[ 9 ];
30
31
32
33
players = new Player[ 2 ];
playerThreads = new Thread[ 2 ];
currentPlayer = 0;
34
35
36
// accept connections on a different thread
getPlayers = new Thread( new ThreadStart( SetUp ) );
getPlayers.Start();
TicTacToeServer.cs
Arrays referencing Player and
Thread objects
(2 of
10)
Keep track of the current
player
Create and start Thread to accept
connections so that the current thread
does not block while awaiting players
37
38
} // end method TicTacToeServerForm_Load
39
40
// notify Players to stop Running
private void TicTacToeServerForm_FormClosing( object sender,
41
42
43
44
Outline
FormClosingEventArgs e )
{
Notify and terminate program and
close its associated threads
disconnected = true;
System.Environment.Exit( System.Environment.ExitCode );
45
} // end method TicTacToeServerForm_FormClosing
46
47
// delegate that allows method DisplayMessage to be called
48
49
// in the thread that creates and maintains the GUI
private delegate void DisplayDelegate( string message );
 2006 Pearson Education,
Inc. All rights reserved.
50
44
51
52
53
// method DisplayMessage sets displayTextBox's Text property
// in a thread-safe manner
internal void DisplayMessage( string message )
54
55
{
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// if modifying displayTextBox is not thread safe
75
TicTacToeServer.cs
if ( displayTextBox.InvokeRequired )
{
// use inherited method Invoke to execute DisplayMessage
// via a delegate
Invoke( new DisplayDelegate( DisplayMessage ),
(3 of 10)
new object[] { message } );
} // end if
else // OK to modify displayTextBox in current thread
displayTextBox.Text += message;
} // end method DisplayMessage
// accepts connections from 2 players
public void SetUp()
{
DisplayMessage( "Waiting for players...\r\n" );
71
72
73
74
Outline
Creates a TcpListerner object to
listen for requests on port 50000
// set up Socket
listener =
new TcpListener( IPAddress.Parse( "127.0.0.1" ), 50000 );
listener.Start();
 2006 Pearson Education,
Inc. All rights reserved.
76
77
// accept first player and start a player thread
78
79
players[ 0 ] = new Player( listener.AcceptSocket(), this, 0 );
playerThreads[ 0 ] =
45
new Thread( new ThreadStart( players[ 0 ].Run ) );
80
81
playerThreads[ 0 ].Start();
Outline
Instantiate Player objects
representing players
TicTacToeServer.cs
82
83
// accept second player and start another player thread
84
85
players[ 1 ] = new Player( listener.AcceptSocket(), this, 1 );
playerThreads[ 1 ] =
86
87
new Thread( new ThreadStart( players[ 1 ].Run ) );
playerThreads[ 1 ].Start();
88
89
90
// let the first player know that the other player has connected
lock ( players[ 0 ] )
91
92
{
93
94
Monitor.Pulse( players[ 0 ] );
} // end lock
Notify and unsuspend the first Player
since other Player has connected
players[ 0 ].threadSuspended = false;
95
96
97
} // end method SetUp
98
99
100
public bool ValidMove( int location, int player )
{
// prevent another thread from making a move
// determine if a move is valid
101
lock ( this )
102
103
104
{
105
(4 ofThreads
10)
Creates two
that
execute the Run methods
of each Player object
Allow only one move to be attempted at a time
// while it is not the current player's turn, wait
while ( player != currentPlayer )
Monitor.Wait( this );
Wait if it’s not the player’s turn
 2006 Pearson Education,
Inc. All rights reserved.
106
107
// if the desired square is not occupied
108
if ( !IsOccupied( location ) )
109
{
Checks to see if the user have
Outline
selected an unoccupied space
110
// set the board to contain the current player's mark
111
board[ location ] = ( byte ) ( currentPlayer == 0 ?
112
113
TicTacToeServer.cs
'X' : 'O' );
114
// set the currentPlayer to be the other player
115
116
currentPlayer = ( currentPlayer + 1 ) % 2;
117
118
119
120
// notify the other player of the move
players[ currentPlayer ].OtherPlayerMoved( location );
121
Monitor.Pulse( this );
return true;
} // end if
124
125
else
return false;
127
Place the mark on the local
(5 of 10)
representation of the board
Determine and set the
currentPlayer to
the appropriate value
// alert the other player that it's time to move
122
123
126
46
} // end lock
Notifies the other player that
a move has been made
Invokes the Pulse method so that the
waiting Player can validate a move
} // end method ValidMove
 2006 Pearson Education,
Inc. All rights reserved.
128
47
129
// determines whether the specified square is occupied
130
131
public bool IsOccupied( int location )
{
132
133
if ( board[ location ] == 'X' || board[ location ] == 'O' )
return true;
134
135
else
return false;
136
} // end method IsOccupied
137
138
// determines if the game is over
139
140
141
public bool GameOver()
{
// place code here to test for a winner of the game
142
143
return false;
} // end method GameOver
Outline
TicTacToeServer.cs
(6 of 10)
144 } // end class TicTacToeServerForm
 2006 Pearson Education,
Inc. All rights reserved.
145
146 // class Player represents a tic-tac-toe player
48
Create instance
variables for
Outline
implementing the player of the
Tic-Tac-Toe networking game
147 public class Player
148 {
149
internal Socket connection; // Socket for accepting a connection
150
151
152
153
private
private
private
private
154
155
156
157
158
159
160
161
private int number; // player number
private char mark; // player’s mark on the board
internal bool threadSuspended = true; // if waiting for other player
162
163
164
165
NetworkStream socketStream; // network data
TicTacToeServerForm server; // reference to
BinaryWriter writer; // facilitates writing
BinaryReader reader; // facilitates reading
TicTacToeServer.cs
(7 of 10)
// constructor requiring Socket, TicTacToeServerForm and int
// objects as arguments
public Player( Socket socket, TicTacToeServerForm serverValue,
int newNumber )
{
mark = (newNumber == 0 ? 'X' : 'O');
connection = socket;
server = serverValue;
166
167
168
number = newNumber;
169
socketStream = new NetworkStream( connection );
170
171
172
// create Streams for reading/writing bytes
writer = new BinaryWriter( socketStream );
173
174
stream
server
to the stream
from the stream
// create NetworkStream object for Socket
Instantiate the NetworkStream
object by passing the Socket
object into the constructor
Instantiate the BinaryWriter
and BinaryReader objects by
passing the NetworkStream
object into the constructor
reader = new BinaryReader( socketStream );
} // end constructor
 2006 Pearson Education,
Inc. All rights reserved.
175
49
176
// signal other player of move
177
public void OtherPlayerMoved( int location )
178
179
180
{
181
182
writer.Write( location ); // send location of move
} // end method OtherPlayerMoved
// signal that opponent moved
writer.Write( "Opponent moved." );
Notify player that theOutline
opponent
has moved via method
Write of BinaryWriter
TicTacToeServer.cs
(8 of 10)
183
184
185
186
// allows the players to make moves and receive moves
// from the other player
public void Run()
187
{
188
189
bool done = false;
190
191
192
193
194
195
196
// display on the server that a connection was made
server.DisplayMessage( "Player " + ( number == 0 ? 'X' : 'O' )
+ " connected\r\n" );
197
// if number equals 0 then this player is X,
198
199
200
// otherwise O must wait for X's first move
writer.Write( "Player " + ( number == 0 ?
"X connected.\r\n" : "O connected, please wait.\r\n" ) );
// send the current player's mark to the client
writer.Write( mark );
Notify the server of a successful
connection and send to the
client the char that the client
will place on the board when
making a move
 2006 Pearson Education,
Inc. All rights reserved.
201
50
202
203
// X must wait for another player to arrive
if ( mark == 'X' )
204
{
Suspends the Player “X” thread until the
server signals that Player O has connected
205
206
writer.Write( "Waiting for another player." );
207
208
// wait for notification from server that another
// player has connected
TicTacToeServer.cs
209
210
lock ( this )
{
(9 of 10)
while ( threadSuspended )
211
Notify player X of the current
situation
212
213
214
Monitor.Wait( this );
} // end lock
215
writer.Write( "Other player connected. Your move." );
216
217
218
} // end if
219
while ( !done )
220
{
// play game
221
222
// wait for data to become available
while ( connection.Available == 0 )
223
{
224
225
226
227
228
`
Outline
Thread.Sleep( 1000 );
Loops until Socket property Available
indicates that there is information to
receive from the Socket
If there is no information, Thread
goes to sleep for one second
if ( server.disconnected )
return;
} // end while
Checks whether server is disconnected
 2006 Pearson Education,
Inc. All rights reserved.
229
51
230
231
// receive data
int location = reader.ReadInt32();
232
233
// if the move is valid, display the move on the
234
235
// server and signal that the move is valid
if ( server.ValidMove( location, number ) )
236
{
237
TicTacToeServer.cs
server.DisplayMessage( "loc: " + location + "\r\n" );
238
239
writer.Write( "Valid move." );
} // end if
240
241
242
243
else // signal that the move is invalid
writer.Write( "Invalid move, try again." );
// if game is over, set done to true to exit while loop
244
if ( server.GameOver() )
245
Validates(10
the of
player’s
10) move
done = true;
246
247
} // end while loop
248
// close the socket connection
249
writer.Close();
250
251
reader.Close();
socketStream.Close();
252
connection.Close();
253
Read in an intOutline
representing
the location in which the
client wants to place a mark
Determine if the game is over
Release program’s resources
by closing its connections
} // end method Run
254 } // end class Player
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 23.6: TicTacToeClient.cs
2
// Client for the TicTacToe program.
3
using System;
4
using System.Drawing;
5
using System.Windows.Forms;
6
using System.Net.Sockets;
7
using System.Threading;
8
using System.IO;
52
Outline
Using namespaces for
networking capabilities
TicTacToeClient.cs
(1 of 13)
9
10 public partial class TicTacToeClientForm : Form
11 {
12
public TicTacToeClientForm()
Create instance variables for
implementing the client side of the
Tic-Tac-Toe networking game
13
14
{
15
16
} // end constructor
17
18
private Square[ , ] board; // local representation of the game board
private Square currentSquare; // the Square that this player chose
19
20
private Thread outputThread; // Thread for receiving data from server
private TcpClient connection; // client to establish connection
21
22
private NetworkStream stream; // network data stream
private BinaryWriter writer; // facilitates writing to the stream
23
24
private BinaryReader reader; // facilitates reading from the stream
private char myMark; // player's mark on the board
25
private bool myTurn; // is it this player's turn?
26
27
private SolidBrush brush; // brush for drawing X's and O's
private bool done = false; // true when game is over
InitializeComponent();
 2006 Pearson Education,
Inc. All rights reserved.
28
53
29
// initialize variables and thread for connecting to server
30
private void TicTacToeClientForm_Load( object sender, EventArgs e )
31
32
33
{
Outline
board = new Square[ 3, 3 ];
34
35
// create 9 Square objects and place them on the board
board[ 0, 0 ] = new Square( board0Panel, ' ', 0 );
TicTacToeClient.cs
36
board[ 0, 1 ] = new Square( board1Panel, ' ', 1 );
(2 of 13)
37
38
39
board[ 0, 2 ] = new Square( board2Panel, ' ', 2 );
board[ 1, 0 ] = new Square( board3Panel, ' ', 3 );
board[ 1, 1 ] = new Square( board4Panel, ' ', 4 );
40
board[ 1, 2 ] = new Square( board5Panel, ' ', 5 );
41
42
board[ 2, 0 ] = new Square( board6Panel, ' ', 6 );
board[ 2, 1 ] = new Square( board7Panel, ' ', 7 );
43
44
45
46
47
48
49
board[ 2, 2 ] = new Square( board8Panel, ' ', 8 );
50
connection = new TcpClient( "127.0.0.1", 50000 );
51
52
53
stream = connection.GetStream();
writer = new BinaryWriter( stream );
reader = new BinaryReader( stream );
Initialize the Tic-Tac-Toe board
Create a black SolidBrush object
for coloring the “X”s and “O”s
// create a SolidBrush for writing on the Squares
brush = new SolidBrush( Color.Black );
// make connection to server and get the associated
// network stream
Instantiate the instance variables
 2006 Pearson Education,
Inc. All rights reserved.
54
54
// start a new thread for sending and receiving messages
outputThread = new Thread( new ThreadStart( Run ) );
55
56
57
58
outputThread.Start();
} // end method TicTacToeClientForm_Load
Outline
Create and start Thread to read messages
sent from the server to the client
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
TicTacToeClient.cs
// repaint the Squares
private void TicTacToeClientForm_Paint( object sender,
PaintEventArgs e )
Repaint the squares by
calling PaintSquare
{
(3 of 13)
PaintSquares();
} // end method TicTacToeClientForm_Load
// game is over
private void TicTacToeClientForm_FormClosing( object sender,
FormClosingEventArgs e )
{
done = true;
System.Environment.Exit( System.Environment.ExitCode );
Notify and terminate program and
close its associated threads
} // end TicTacToeClientForm_FormClosing
74
75
// delegate that allows method DisplayMessage to be called
76
77
// in the thread that creates and maintains the GUI
private delegate void DisplayDelegate( string message );
 2006 Pearson Education,
Inc. All rights reserved.
78
55
79
// method DisplayMessage sets displayTextBox's Text property
80
// in a thread-safe manner
81
82
private void DisplayMessage( string message )
{
83
// if modifying displayTextBox is not thread safe
84
85
if ( displayTextBox.InvokeRequired )
{
86
// use inherited method Invoke to execute DisplayMessage
87
// via a delegate
88
89
Invoke( new DisplayDelegate( DisplayMessage ),
new object[] { message } );
90
91
92
Outline
TicTacToeClient.cs
(4 of 13)
} // end if
else // OK to modify displayTextBox in current thread
displayTextBox.Text += message;
93
} // end method DisplayMessage
94
95
// delegate that allows method ChangeIdLabel to be called
96
// in the thread that creates and maintains the GUI
97
private delegate void ChangeIdLabelDelegate( string message );
 2006 Pearson Education,
Inc. All rights reserved.
98
56
99
// method ChangeIdLabel sets displayTextBox's Text property
100
101
// in a thread-safe manner
private void ChangeIdLabel( string label )
102
{
103
// if modifying idLabel is not thread safe
104
if ( idLabel.InvokeRequired )
105
106
107
108
109
110
111
112
113
Outline
TicTacToeClient.cs
{
// use inherited method Invoke to execute ChangeIdLabel
// via a delegate
Invoke( new ChangeIdLabelDelegate( ChangeIdLabel ),
(5 of 13)
new object[] { label } );
} // end if
else // OK to modify idLabel in current thread
idLabel.Text = label;
} // end method ChangeIdLabel
 2006 Pearson Education,
Inc. All rights reserved.
114
57
115
// draws the mark of each square
116
public void PaintSquares()
117
118
{
Graphics g;
Outline
Create an instance of
Graphics for repainting
119
120
121
// draw the appropriate mark on each panel
for ( int row = 0; row < 3; row++ )
122
{
123
for ( int column = 0; column < 3; column++ )
124
125
{
TicTacToeClient.cs
(6 of the
13) Graphics
Retrieve and reference
object for each Panel
// get the Graphics for each Panel
126
127
g = board[ row, column ].SquarePanel.CreateGraphics();
128
// draw the appropriate letter on the panel
129
g.DrawString( board[ row, column ].Mark.ToString(),
130
131
132
133
board0Panel.Font, brush, 10, 8 );
} // end for
Mark the appropriate square
} // end for
} // end method PaintSquares
 2006 Pearson Education,
Inc. All rights reserved.
134
135
136
58
// send location of the clicked square to server
private void square_MouseUp( object sender,
System.Windows.Forms.MouseEventArgs e )
137
138
{
139
// for each square check if that square was clicked
140
141
for ( int row = 0; row < 3; row++ )
{
142
143
144
145
(7 of 13)
if ( board[ row, column ].SquarePanel == sender )
{
CurrentSquare = board[ row, column ];
148
// send the move to the server
151
152
TicTacToeClient.cs
for ( int column = 0; column < 3; column++ )
{
146
147
149
150
Outline
Determine and update which
square was clicked
SendClickedSquare( board[ row, column ].Location );
} // end if
} // end for
} // end for
153
154
} // end method square_MouseUp
155
156
157
// control thread that allows continuous update of the
// TextBox display
public void Run()
158 {
159
// first get players's mark (X or O)
160
161
myMark = reader.ReadChar();
ChangeIdLabel( "You are player \"" + myMark + "\"" );
162
myTurn = ( myMark == 'X' ? true : false );
Notify the server of
the clicked square
Get and output the
player’s mark
 2006 Pearson Education,
Inc. All rights reserved.
163
59
164
// process incoming messages
165
try
166
{
167
// receive messages sent to client
168
while ( !done )
Invoke ProcessMessage
with the return
Outline
value of ReadString of the
BinaryReader object as the argument
170
} // end try
171
catch ( IOException )
172
{
175
176
} // end catch
} // end method Run
177
178
// process messages sent to client
179
180
public void ProcessMessage( string message )
{
181
182
// if the move the player sent to the server is valid
// update the display, set that square's mark to be
183
184
// the mark of the current player and repaint the board
if ( message == "Valid move." )
185
186
{
188
189
(8 of 13)
MessageBox.Show( "Server is down, game over", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error );
173
174
187
TicTacToeClient.cs
ProcessMessage( reader.ReadString() );
169
DisplayMessage( "Valid move, please wait.\r\n" );
currentSquare.Mark = myMark;
PaintSquares();
} // end if
If the message indicates that a
move is valid, the client sets
its Mark to the current square
and repaints the board
 2006 Pearson Education,
Inc. All rights reserved.
190
else if ( message == "Invalid move, try again." )
191
192
{
// if the move is invalid, display that and it is now
// this player's turn again
DisplayMessage( message + "\r\n" );
193
194
195
196
myTurn = true;
} // end else if
197
else if ( message == "Opponent moved." )
198
{
60
If the message indicates
Outlinethat a move
is invalid, the client notifies the
user to click a different square
Update the player’s turn
TicTacToeClient.cs
(9 of 13)
199
200
// if opponent moved, find location of their move
int location = reader.ReadInt32();
201
202
203
204
// set that square to have the opponents mark and
// repaint the board
board[ location / 3, location % 3 ].Mark =
If the message indicates that the
opponent made a move, read an
int from the server specifying
where on the board the client
should place the opponent’s Mark
( myMark == 'X' ? 'O' : 'X' );
205
206
PaintSquares();
207
208
DisplayMessage( "Opponent moved.
Your turn.\r\n" );
209
210
// it is now this player's turn
211
212
myTurn = true;
} // end else if
213
else
214
215
Update the player’s turn
DisplayMessage( message + "\r\n" ); // display message
} // end method ProcessMessage
Display the read message
 2006 Pearson Education,
Inc. All rights reserved.
216
61
217
218
// sends the server the number of the clicked square
public void SendClickedSquare( int location )
219
220
{
// if it is the current player's move right now
221
if ( myTurn )
222
223
{
Determine which player’s turn it is
(10 of
Notify the location of the move
via13)
BinaryWriter’s method Write
writer.Write( location );
226
227
228
229
230
// it is now the other player's turn
myTurn = false;
Update the
} // end if
} // end method SendClickedSquare
231
232
233
// write-only property for the current square
public Square CurrentSquare
{
234
set
235
{
237
TicTacToeClient.cs
// send the location of the move to the server
224
225
236
Outline
player’s turn
currentSquare = value;
} // end set
238
} // end property CurrentSquare
239 } // end class TicTacToeClientForm
 2006 Pearson Education,
Inc. All rights reserved.
62
At the start of the game.
(a)
Outline
(b)
TicTacToeClient.cs
(11 of 13)
After Player X makes the first move.
(c)
(d)
 2006 Pearson Education,
Inc. All rights reserved.
63
After Player O makes the second move.
(e)
Outline
(f)
TicTacToeClient.cs
(12 of 13)
After Player X makes the final move.
(g)
(h)
 2006 Pearson Education,
Inc. All rights reserved.
64
Outline
The Tie Tac Toe Server’s output from the client interactions
server output after (a,b)
server output after (c,d)
(i)
TicTacToeClient.cs
(13 of 13)
server output after (e,f)
server output after (g,h)
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 23.7: Square.cs
2
// A Square on the TicTacToe board.
3
using System.Windows.Forms;
4
5
// the representation of a square in a tic-tac-toe grid
6
public class Square
7
8
{
9
10
Outline
Square.cs
private Panel panel; // GUI Panel that represents this Square
private char mark; // player’s mark on this Square (if any)
private int location; // location on the board of this Square
11
12
13
14
65
// constructor
public Square( Panel newPanel, char newMark, int newLocation )
{
(1 of 2)
Represents a square in the
Tic-Tac-Toe game
panel = newPanel;
mark = newMark;
location = newLocation;
15
16
17
18
19
20
21
} // end constructor
22
23
24
{
25
26
27
return panel;
} // end get
} // end property SquarePanel
// property SquarePanel; the panel which the square represents
public Panel SquarePanel
get
{
 2006 Pearson Education,
Inc. All rights reserved.
28
29
30
31
32
33
66
// property Mark; the mark on the square
public char Mark
Outline
{
get
{
return mark;
34
35
36
} // end get
set
37
38
39
{
Square.cs
(2 of 2)
mark = value;
} // end set
40
41
} // end property Mark
42
// property Location; the square's location on the board
43
44
public int Location
{
45
get
46
47
{
return location;
48
} // end get
49
} // end property Location
50 } // end class Square
 2006 Pearson Education,
Inc. All rights reserved.
67
23.9 WebBrowser Control
•WebBrowser control
- Enables applications to incorporate Web browsing
capabilities
- Generates events as the user interacts with the content
displayed in the control
• Applications can respond to these events
- Properties CanGoBack and CanGoForward
• Determine whether the back and forward buttons are
enabled
 2006 Pearson Education, Inc. All rights reserved.
68
23.9 WebBrowser Control (Cont.)
• WebBrowser methods
- Method GoBack
• Causes the control to navigate back to the previous page in the
navigation history
- Method GoForward
• Causes the control to navigate forward to the next page in the
navigation history
-
Method Stop
• Causes the control to stop loading the current page
- Method Refresh
• Causes the control to reload the current page
-
Method GoHome
• Causes the control to navigate to the user’s home page, as defined
under Internet Explorer’s settings
- Method Navigate
• Retrieve the document at the specified URL
 2006 Pearson Education, Inc. All rights reserved.
69
23.9 WebBrowser Control (Cont.)
• WebBrowser’s Events
- Navigating event
• Occurs when the WebBrowser starts loading a new page
- StatusTextChanged event
• Occurs when the WebBrowser’s StatusText property changes
- ProgressChanged event
• Occurs when the WebBrowser control’s page-loading progress is
updated
- DocumentCompleted event
• Occurs when the WebBrowser finishes loading a document
- DocumentTitleChanged event
• Occurs when a new document is loaded in the WebBrowser control
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 23.8: Browser.cs
2
// WebBrowser control example.
3
using System;
4
using System.Windows.Forms;
70
Outline
5
6
public partial class BrowserForm : Form
7 {
8
9
10
Browser.cs
public BrowserForm()
{
InitializeComponent();
(1 of 4)
11
12
} // end constructor
13
14
// navigate back one page
private void backButton_Click( object sender, EventArgs e )
15
16
17
18
{
19
20
21
22
23
// navigate forward one page
private void forwardButton_Click( object sender, EventArgs e )
{
webBrowser.GoForward();
Navigate forward
} // end method forwardButton_Click
24
25
26
27
// stop loading the current page
private void stopButton_Click( object sender, EventArgs e )
{
28
29
webBrowser.Stop();
} // end method stopButton_Click
webBrowser.GoBack();
} // end method backButton_Click
Navigate back to the previous
page in the navigation history
to the next
page in the navigation history
Stop loading the current page
 2006 Pearson Education,
Inc. All rights reserved.
30
71
31
// reload the current page
32
private void reloadButton_Click( object sender, EventArgs e )
33
34
{
35
} // end method reloadButton_Click
webBrowser.Refresh();
Outline
Reload the current page
Browser.cs
36
37
// navigate to the user's home page
38
39
private void homeButton_Click( object sender, EventArgs e )
{
webBrowser.GoHome();
40
(2 of 4)
Navigate to the user’s homepage
41
42
43
} // end method homeButton_Click
44
45
46
private void navigationTextBox_KeyDown( object sender,
KeyEventArgs e )
{
47
48
49
50
if ( e.KeyCode == Keys.Enter )
webBrowser.Navigate( navigationTextBox.Text );
} // end method navigationTextBox_KeyDown
51
52
53
// enable stopButton while the current page is loading
private void webBrowser_Navigating( object sender,
Event
WebBrowserNavigatingEventArgs e )
54
55
56
{
// if the user pressed enter, navigate to the specified URL
stopButton.Enabled = true;
} // end method webBrowser_Navigating
Navigate to the user specified URL
occurs when loading a new page
Enable the stop button
 2006 Pearson Education,
Inc. All rights reserved.
57
58
59
60
// update the status text
Event occurs when
private void webBrowser_StatusTextChanged( object sender,
EventArgs e )
61
{
62
63
64
65
statusTextBox.Text = webBrowser.StatusText;
} // end method webBrowser_StatusTextChanged
66
67
private void webBrowser_ProgressChanged( object sender,
WebBrowserProgressChangedEventArgs e )
68
69
70
{
71
} // end method webBrowser_ProgressChanged
72
73
74
75
76
77
78
79
80
81
82
83
84
85
72
the StatusText
property changes
Outline
Assigns the new contents of the
control’s StatusText property to
statusTextBox’s
Text property
Browser.cs
(3 of 4)
// update the ProgressBar for how much of the page has been loaded
Event occurs when the page-loading progress is updated
pageProgressBar.Value =
( int ) ( ( 100 * e.CurrentProgress ) / e.MaximumProgress );
Update pageProgressBar’s Value to reflect how
appropriately much of the current document has been loaded
// update the web browser's controls
private void webBrowser_DocumentCompleted( object sender,
WebBrowserDocumentCompletedEventArgs e )
Event occurs when
{
// set the text in navigationTextBox to the current page's URL
navigationTextBox.Text = webBrowser.Url.ToString();
// enable or disable backButton and forwardButton
backButton.Enabled = webBrowser.CanGoBack;
forwardButton.Enabled = webBrowser.CanGoForward;
// disable stopButton
stopButton.Enabled = false;
Disable the stop button
finish loading a document
Update to show the URL of
currently loaded page
Determine whether the back and
forward buttons should be
enabled or disabled
 2006 Pearson Education,
Inc. All rights reserved.
86
73
// clear the pageProgressBar
pageProgressBar.Value = 0;
87
88
89
Outline
Indicates that no content is currently being loaded
} // end method webBrowser_DocumentCompleted
90
91
// update the title of the Browser
92
93
private void webBrowser_DocumentTitleChanged( object sender,
EventArgs e )
94
95
{
Browser.cs
Event occurs when a new document is loaded
(4 of 4)
this.Text = webBrowser.DocumentTitle + " - Browser";
96
} // end method webBrowser_DocumentTitleChanged
97 } // end class BrowserForm
Sets the BrowserForm’s
Text property to the
WebBrowser’s current
DocumentTitle
 2006 Pearson Education,
Inc. All rights reserved.
74
23.10 .NET Remoting
• .NET Remoting
- System.Runtime.Remoting
- A distributed computing technology
- Allows a program to access objects on another machine over
a network
- For .NET remoting, both must be written in .NET languages
- Marshaling the objects
• A client and a server can communicate via method calls and
objects can be transmitted between applications
 2006 Pearson Education, Inc. All rights reserved.
75
23.10 .NET Remoting (Cont.)
• Channels
- The client and the server are able to communicate with one
another through channels
- The client and the server each create a channel
• Both channels must use the same protocol to communicate with one
another
- HTTP channel
• Firewall usually permit HTTP connections by default
- TCP channel
• Better performance than an HTTP channel
• Firewalls normally block unfamiliar TCP connections
- System.Runtime.Remoting.Channels
- System.Runtime.Remoting.Channels.Http
 2006 Pearson Education, Inc. All rights reserved.
76
23.10 .NET Remoting (Cont.)
• Marshalling
- Marshaling by value
• Requires that the object be serializable
- Marshaling by reference
• Requires that the object’s class extend class
MarshalByRefObject of namespace System
• The object itself is not transmitted
- Instead, two proxy objects are created
• Transparent proxy
- Provides all the public services of a remote object
- Calls the Invoke method of the real proxy
• Real proxy
 2006 Pearson Education, Inc. All rights reserved.
1
2
// Fig. 23.9: CityWeather.cs
// Class representing the weather information for one city.
3
using System;
4
5
namespace Weather
6
7
8
9
10
{
[ Serializable ]
public class CityWeather : IComparable
{
private string cityName;
private string description;
private string temperature;
13
14
public CityWeather( string city, string information,
CityWeather.cs
Indicates that an object
of this class
can be marshaled by value
(1 of 3)
Implements interface IComparable
so that the ArrayList of
CityWeather objects can be
sorted alphabetically
string degrees )
{
17
cityName = city;
18
description = information;
19
temperature = degrees;
20
21
22
} // end constructor
23
24
public string CityName
{
// read-only property that gets city's name
25
get
26
27
{
28
29
Outline
The class will be published in the
Weather.dll class library file
11
12
15
16
77
return cityName;
} // end get
} // end property CityName
 2006 Pearson Education,
Inc. All rights reserved.
30
78
31
// read-only property that gets city's weather description
32
33
public string Description
{
34
get
35
{
return description;
36
37
} // end property Description
41
42
43
public string Temperature
{
get
46
47
CityWeather.cs
} // end get
38
39
40
44
45
Outline
(2 of 3)
// read-only property that gets city's temperature
{
return temperature;
} // end get
} // end property Temperature
 2006 Pearson Education,
Inc. All rights reserved.
48
79
49
// implementation of CompareTo method for alphabetizing
50
51
public int CompareTo( object other )
{
return string.Compare(
52
CityName, ( ( CityWeather ) other ).CityName );
53
54
} // end method Compare
Outline
Must declare CompareTo since
implementedCityWeather.cs
IComparable
55
56
57
58
// return string representation of this CityWeather object
// (used to display the weather report on the server console)
public override string ToString()
Update
59
60
61
{
(3 of 3)
and override ToString
return cityName + " | " + temperature + " | " + description;
} // end method ToString
62
} // end class CityWeather
63 } // end namespace Weather
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 23.10: Report.cs
2
// Interface that defines a property for getting
3
// the information in a weather report.
4
using System;
5
using System.Collections;
6
7
namespace Weather
8
{
9
public interface Report
10
{
11
ArrayList Reports
12
{
13
14
15
get;
} // end property Reports
} // end interface Report
80
Interface will also be included in the
Weather.dll class library
Outline
Report.cs
Interface include read-only property
Reports of type ArrayList
16 } // end namespace Weather
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 23.11: ReportInfo.cs
2
3
// Class that implements interface Report, retrieves
// and returns data on weather
4
5
6
7
8
9
using
using
using
using
using
System;
System.Collections;
System.IO;
System.Net;
Weather;
81
Using Weather.dll class library
10 public class ReportInfo : MarshalByRefObject, Report
11 {
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Outline
ReportInfo.cs
Extends MarshalByRefObject
(1 of 4)
and implements Report
private ArrayList cityList; // cities, temperatures, descriptions
public ReportInfo()
{
cityList = new ArrayList();
Declare data structure to hold information
Interact with a data source specified by a URL
// create WebClient to get access to Web page
WebClient myClient = new WebClient();
// get StreamReader for response so we can read page
StreamReader input = new StreamReader( myClient.OpenRead(
Return a stream that the program can
use to read data containing the
weather information from the URL
"http://iwin.nws.noaa.gov/iwin/us/traveler.html" ) );
string separator1 = "TAV12"; // indicates first batch of cities
26
27
28
29
string separator2 = "TAV13"; // indicates second batch of cities
30
ReadCities( input ); // read the first batch of cities
Store separators
Read the HTML markup
one line at a time
// locate separator1 in Web page
while ( !input.ReadLine().StartsWith( separator1 ) ); // do nothing
Call ReadCities to read the first batch of cities
 2006 Pearson Education,
Inc. All rights reserved.
31
32
82
// locate separator2 in Web page
33
34
35
36
while ( !input.ReadLine().StartsWith( separator2 ) ); // do nothing
ReadCities( input ); // read the second batch of cities
37
input.Close(); // close StreamReader to NWS server
ReadOutline
the HTML markup
one line at a time
Call ReadCities to read the second batch of cities
cityList.Sort(); // sort list of cities by alphabetical order
38
39
// display the data on the server side
40
Console.WriteLine( "Data from NWS Web site:" );
41
42
43
44
45
foreach ( CityWeather city in cityList )
{
Console.WriteLine( city );
} // end foreach
46
47
} // end constructor
48
49
50
// utility method that reads a batch of cities
private void ReadCities( StreamReader input )
{
51
// day format and night format
52
string dayFormat =
53
54
"CITY
WEA
string nightFormat =
HI/LO
WEA
HI/LO";
55
56
"CITY
WEA
string inputLine = "";
LO/HI
WEA
LO/HI";
ReportInfo.cs
Sort the CityWeather
(2 of 4)
objects in alphabetical order
by city name
The header for the
daytime/nighttime information
 2006 Pearson Education,
Inc. All rights reserved.
57
83
58
// locate header that begins weather information
59
60
do
{
61
62
inputLine = input.ReadLine();
} while ( !inputLine.Equals( dayFormat ) &&
ReportInfo.cs
!inputLine.Equals( nightFormat ) );
63
64
65
inputLine = input.ReadLine(); // get first city's data
66
67
68
69
// while there are more cities to read
while ( inputLine.Length > 28 )
{
70
// create CityWeather object for city
71
CityWeather weather = new CityWeather(
72
73
inputLine.Substring( 0, 16 ),
inputLine.Substring( 16, 7 ),
74
inputLine.Substring( 23, 7 ) );
75
76
77
78
79
Continue to Outline
read the page one
line at a time until it finds
the header line
(3 line
of 4)from the
Reads the next
Web page, which is the
first line containing
temperature information
Create a new CityWeather object
to represent the current city
cityList.Add( weather ); // add to ArrayList
inputLine = input.ReadLine(); // get next city's data
Store the CityWeather
object in the ArrayList
} // end while
} // end method ReadCities
Continue by reading the next
city’s information
 2006 Pearson Education,
Inc. All rights reserved.
80
84
81
82
// property for getting the cities’ weather reports
public ArrayList Reports
83
{
84
85
86
87
88
get
{
return cityList;
} // end get
} // end property Reports
Declare read-only property
Reports to satisfy the
Report interface
Outline
ReportInfo.cs
(4 of 4)
89 } // end class ReportInfo
 2006 Pearson Education,
Inc. All rights reserved.
85
23.10 .NET Remoting (Cont.)
• Class WebClient
- Interact with a data source that is specified by a URL
- Method OpenRead
• Returns a Stream that the program can use to read data from the
specified URL
• Remote class registered as Singleton
- One remote object will be created when the first client requests
that remote class
• The remote object will service all clients
• Remote class registered as SingleCall
- One remote object is created for each individual remote method
call to the remote class
 2006 Pearson Education, Inc. All rights reserved.
1
// Fig. 23.12: WeatherServer.cs
2
3
4
// Server application that uses .NET remoting to send
// weather report information to a client
using System;
5
using System.Runtime.Remoting;
6
7
8
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Weather;
9
10 class WeatherServer
11 {
12
static void Main( string[] args )
13
14
{
86
Using namespaces for
remoting capabilities
WeatherServer.cs
Register an HTTP channel
on the current machine
at port 50000
// establish HTTP channel
15
16
17
HttpChannel channel = new HttpChannel( 50000 );
ChannelServices.RegisterChannel( channel, false );
18
19
20
// register ReportInfo class
RemotingConfiguration.RegisterWellKnownServiceType(
typeof( ReportInfo ), "Report",
21
22
23
Outline
WellKnownObjectMode.Singleton );
Console.WriteLine( "Press Enter to terminate server." );
24
Console.ReadLine();
25
} // end Main
26 } // end class WeatherServer
Indicates that we do not
wish to enable security
Register the ReportInfo class
type at the “Report” URI as a
Singleton remote class
 2006 Pearson Education,
Inc. All rights reserved.
1
// Fig. 23.13: WeatherClient.cs
2
// Client that uses .NET remoting to retrieve a weather report.
3
using System;
4
using System.Collections;
5
using System.Drawing;
6
using System.Windows.Forms;
7
8
9
10
using
using
using
using
System.Runtime.Remoting;
System.Runtime.Remoting.Channels;
System.Runtime.Remoting.Channels.Http;
Weather;
87
Using namespaces for
remoting capabilities
Outline
WeatherClient.cs
(1 of 5)
11
12 public partial class WeatherClientForm : Form
13 {
14
15
16
17
public WeatherClientForm()
{
InitializeComponent();
} // end constructor
18
19
20
21
22
// retrieve weather data
private void WeatherClientForm_Load( object sender, EventArgs e )
{
// setup HTTP channel, does not need to provide a port number
23
HttpChannel channel = new HttpChannel();
24
25
26
27
ChannelServices.RegisterChannel( channel, false );
28
Create a HTTP channel without
specifying a port number
// obtain a proxy for an object that implements interface Report
Report info = ( Report ) RemotingServices.Connect(
Register the channel on
the client computer
Connects to the server and
returns a reference to
the proxy for the
Report object
typeof( Report ), "http://localhost:50000/Report" );
 2006 Pearson Education,
Inc. All rights reserved.
29
88
30
// retrieve an ArrayList of CityWeather objects
31
32
ArrayList cities = info.Reports;
33
// create array and populate it with every Label
34
Label[] cityLabels = new Label[ 43 ];
35
int labelCounter = 0;
36
37
38
39
40
41
42
43
44
foreach ( Control control in displayPanel.Controls )
{
if ( control is Label )
{
Retrieve the ArrayList
Outline of
CityWeather objects generated
by the ReportInfo constructor
WeatherClient.cs
Create and place an array of Label
(2 of 5)
so they can be access
programmatically to display
weather information
cityLabels[ labelCounter ] = ( Label ) control;
++labelCounter; // increment Label counter
} // end if
} // end foreach
 2006 Pearson Education,
Inc. All rights reserved.
45
46
// create Hashtable and populate with all weather conditions
47
48
Hashtable weather = new Hashtable();
weather.Add( "SUNNY", "sunny" );
49
weather.Add( "PTCLDY", "pcloudy" );
50
51
52
53
weather.Add(
weather.Add(
weather.Add(
weather.Add(
54
55
56
weather.Add( "SNOW", "snow" );
weather.Add( "VRYHOT", "vryhot" );
weather.Add( "FAIR", "fair" );
57
weather.Add( "RNSNOW", "rnsnow" );
58
weather.Add( "SHWRS", "showers" );
59
60
weather.Add( "WINDY", "windy" );
weather.Add( "NOINFO", "noinfo" );
61
62
63
64
weather.Add(
weather.Add(
weather.Add(
weather.Add(
65
weather.Add( "SNOWSHWRS", "snow" );
66
weather.Add( "FLRRYS", "snow" );
67
weather.Add( "FOG", "noinfo" );
68
69
70
// create the font for the text output
Font font = new Font( "Courier New", 8, FontStyle.Bold );
89
"CLOUDY", "mcloudy" );
"MOCLDY", "mcloudy" );
"TSTRMS", "rain" );
"RAIN", "rain" );
Outline
Store pairs of weather conditions
and the names for images
associate with those conditions
WeatherClient.cs
(3 of 5)
"MISG", "noinfo" );
"DRZL", "rain" );
"HAZE", "noinfo" );
"SMOKE", "mcloudy" );
 2006 Pearson Education,
Inc. All rights reserved.
71
90
72
73
// for every city
for ( int i = 0; i < cities.Count; i++ )
74
{
75
76
Outline
Retrieve the Label that
will display the
weather information for the next city
// use array cityLabels to find the next Label
Label currentCity = cityLabels[ i ];
77
78
// use ArrayList
79
CityWeather city
Uses ArrayList cities to retrieve the
WeatherClient.cs
CityWeather object
that contains the
cities to find the next CityWeather object
weather information for the city
= ( CityWeather ) cities[ i ];
(4 of 5)
80
81
82
// set current Label's image to image
// corresponding to the city's weather condition -
83
84
// find correct image name in Hashtable weather
currentCity.Image = new Bitmap( @"images\" +
85
Set the Label’s image to the PNG
image from the Hashtable
weather[ city.Description.Trim() ] + ".png" );
86
87
currentCity.Font = font; // set font of Label
currentCity.ForeColor = Color.White; // set text color of Label
88
89
90
// set Label's text to city name and temperature
currentCity.Text = "\r\n " + city.CityName + city.Temperature;
91
} // end for
92
} // end method WeatherClientForm_Load
93 } // end class WeatherClientForm
Display the city’s name and
high/low temperatures
 2006 Pearson Education,
Inc. All rights reserved.
91
Outline
WeatherClient.cs
(5 of 5)
 2006 Pearson Education,
Inc. All rights reserved.