Download Week5

Document related concepts
no text concepts found
Transcript
1
Week 5 - Networking
Outline
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
5.10
Introduction
Manipulating URLs
Reading a File on a Web Server
Establishing a Simple Server Using Stream Sockets
Establishing a Simple Client Using Stream Sockets
Client/Server Interaction with Stream Socket Connections
Connectionless Client/Server Interaction with Datagrams
Client/Server Tic-Tac-Toe Using a Multithreaded Server
Security and the Network
DeitelMessenger Chat Server and Client
5.10.1 DeitelMessengerServer and Supporting Classes
5.10.2 DeitelMessenger Client and Supporting Classes
 2002 Prentice Hall, Inc. All rights reserved.
2
Week 5 - Networking
Outline (cont.)
5.11
(Optional) Discovering Design Patterns: Design Patterns Used
in Packages java.io and java.net
5.11.1 Creational Design Patterns
5.11.2 Structural Design Patterns
5.11.3 Architectural Patterns
5.11.4 Conclusion
 2002 Prentice Hall, Inc. All rights reserved.
3
5.1 Introduction
• Networking package is java.net
– Socket-based communications
• Applications view networking as streams of data
• Connection-based protocol
• Uses TCP (Transmission Control Protocol
– Packet-based communications
• Individual packets transmitted
• Connectionless service
• Uses UDP (User Datagram Protocol)
 2002 Prentice Hall, Inc. All rights reserved.
4
5.2 Manipulating URIs
• HyperText Transfer Protocol (HTTP)
– Uses URIs (Uniform Resource Identifiers) to locate data
• URIs frequently called URLs (Uniform Resource Locators)
• Refer to files, directories and complex objects
 2002 Prentice Hall, Inc. All rights reserved.
5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<title>Site Selector</title>
<body>
<applet code = "SiteSelector.class" width = "300" height = "75">
<param name = "title0" value = "Java Home Page">
<param name = "location0" value = "http://java.sun.com/">
<param name = "title1" value = "Deitel">
<param name = "location1" value = "http://www.deitel.com/">
<param name = "title2" value = "JGuru">
<param name = "location2" value = "http://www.jGuru.com/">
<param name = "title3" value = "JavaWorld">
<param name = "location3" value = "http://www.javaworld.com/">
</applet>
</body>
</html>
Outline
SiteSelector.html
 2002 Prentice Hall, Inc.
All rights reserved.
6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Outline
// Fig. 5.2: SiteSelector.java
// This program uses a button to load a document from a URL.
// Java core packages
import java.net.*;
import java.util.*;
import java.awt.*;
import java.applet.AppletContext;
SiteSelector.java
Lines
20-63init
Method
initializes applet
Lines 23-24
// Java extension packages
import javax.swing.*;
import javax.swing.event.*;
public class SiteSelector extends
private Hashtable sites;
//
private Vector siteNames;
//
private JList siteChooser; //
Line 27
JApplet {
site names and URLs
site names
list of sites to choose from
// read HTML parameters and set up GUI
public void init()
{
// create Hashtable and Vector
sites = new Hashtable();
siteNames = new Vector();
// obtain parameters from HTML document
getSitesFromHTMLParameters();
// create GUI components and layout interface
Container container = getContentPane();
container.add( new JLabel( "Choose a site to browse" ),
BorderLayout.NORTH );
Lines
Create31-32
HashTable
and Vector objects
Obtain HTML
parameters from
HTML document that
invoked applet
Add JLabel to
applet
 2002 Prentice Hall, Inc.
All rights reserved.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
siteChooser = new JList( siteNames );
siteChooser.addListSelectionListener(
Register anonymous
inner class
Outline
that implements
ListSelectionListener
new ListSelectionListener() {
// go to site user selected
public void valueChanged( ListSelectionEvent event )
{
// get selected site name
Object object = siteChooser.getSelectedValue();
// use site name to locate corresponding URL
URL newDocument = ( URL ) sites.get( object );
// get reference to applet container
AppletContext browser = getAppletContext();
}
}
SiteSelector.java
Lines 36-58
Lines 41-54
Lines Method
60-61
valueChanged
goes to the selected
Web site
// tell applet container to change pages
browser.showDocument( newDocument );
// end method valueChanged
// end anonymous inner class
); // end call to addListSelectionListener
container.add( new JScrollPane( siteChooser ),
BorderLayout.CENTER );
}
7
Add siteChooser
to applet
// end method init
 2002 Prentice Hall, Inc.
All rights reserved.
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
8
Method
Outline
getSitesfromHTMLParameters
gets parameters from HTML document
// obtain parameters from HTML document
private void getSitesFromHTMLParameters()
{
// look for applet parameters in the HTML document
// and add sites to Hashtable
String title, location;
URL url;
int counter = 0;
// obtain first site title
title = getParameter( "title" + counter );
// loop until no more parameters in HTML document
while ( title != null ) {
// obtain site location
location = getParameter( "location" + counter );
// place title/URL in Hashtable and title in Vector
try {
// convert location to URL
url = new URL( location );
SiteSelector.java
Get Web site title
Lines 66-108
If title
Line
75 is not null,
execute loop
Lines 78-106
Line
81 site location
Get Web
Line 87
Create URL of
Line 90location
Line 93
Add URL to
Hashtable
// put title/URL in Hashtable
sites.put( title, url );
// put title in Vector
siteNames.add( title );
Add title to
Vector
}
 2002 Prentice Hall, Inc.
All rights reserved.
9
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// process invalid URL format
catch ( MalformedURLException urlException ) {
urlException.printStackTrace();
}
++counter;
// obtain next site title
title = getParameter( "title" + counter );
}
}
}
Outline
SiteSelector.java
Line 104
Get next title from
HTML document
// end while
// end method getSitesFromHTMLParameters
// end class SiteSelector
 2002 Prentice Hall, Inc.
All rights reserved.
10
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
11
5.3 Reading a File on a Web Server
• Swing GUI component JEditorPane
– Can display simple text and HTML formatted text
– Can be used as a simple Web browser
• Retrieves files from a Web server at a given URI
 2002 Prentice Hall, Inc. All rights reserved.
12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Outline
// Fig. 5.3: ReadServerFile.java
// This program uses a JEditorPane to display the
// contents of a file on a Web server.
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
// Java extension packages
import javax.swing.*;
import javax.swing.event.*;
public class ReadServerFile extends JFrame {
private JTextField enterField;
private JEditorPane contentsArea;
// set up GUI
public ReadServerFile()
{
super( "Simple Web Browser" );
ReadServerFile.java
Line 16
Line 17
Write URI in
JTextField
File displayed in
JEditorPane
Container container = getContentPane();
// create enterField and register its listener
enterField = new JTextField( "Enter file URL here" );
 2002 Prentice Hall, Inc.
All rights reserved.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
enterField.addActionListener(
new ActionListener() {
// get document specified by user
public void actionPerformed( ActionEvent event )
{
getThePage( event.getActionCommand() );
}
}
// end anonymous inner class
); // end call to addActionListener
container.add( enterField, BorderLayout.NORTH );
// create contentsArea and register HyperlinkEvent listener
contentsArea = new JEditorPane();
contentsArea.setEditable( false );
contentsArea.addHyperlinkListener(
new HyperlinkListener() {
// if user clicked hyperlink, go to specified page
public void hyperlinkUpdate( HyperlinkEvent event )
{
if ( event.getEventType() ==
HyperlinkEvent.EventType.ACTIVATED )
getThePage( event.getURL().toString() );
}
}
// end anonymous inner class
); // end call to addHyperlinkListener
13
Method
Outline
actionPerformed
called when Enter key
ReadServerFile.java
pressed in
JTextField
Lines 34-37
Get String from
JTextField and
Lines call
49-63
method
getThePage
Line 36
Lines 54-59
Register
Lines
56-57
a
HyperlinkListener
Lineto58handle
HyperlinkEvents
Method
hyperlinkUpdate
called when hyperlink
clicked
Determine type of
hyperlink
Get URL of hyperlink
and retrieve page
 2002 Prentice Hall, Inc.
All rights reserved.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
container.add( new JScrollPane( contentsArea ),
BorderLayout.CENTER );
Method
Outline
getThePage loads
requested document
ReadServerFile.java
setSize( 400, 300 );
setVisible( true );
}
Lines 73-95
// load document; change mouse cursor to indicate status
private void getThePage( String location )
{
// change mouse cursor to WAIT_CURSOR
setCursor( Cursor.getPredefinedCursor(
Cursor.WAIT_CURSOR ) );
Lines
76-77
WAIT_CURSOR
Set mouse cursor to
// load document into contentsArea and display location in
// enterField
try {
contentsArea.setPage( location );
enterField.setText( location );
}
// process problems loading document
catch ( IOException ioException ) {
JOptionPane.showMessageDialog( this,
"Error retrieving specified URL",
"Bad URL", JOptionPane.ERROR_MESSAGE );
}
setCursor( Cursor.getPredefinedCursor(
Cursor.DEFAULT_CURSOR ) );
}
14
Set cursor to
DEFAULT_CURSOR
Line 82
Line 83
Method
Lines
87-91setPage
downloads document
Lines
and93-94
displays it in
JEditorPane
Display current
location in
enterField
Catch
IOException if
document fails to
load
 2002 Prentice Hall, Inc.
All rights reserved.
15
97
98
99
100
101
102
103
104
105
106
// begin application execution
public static void main( String args[] )
{
ReadServerFile application = new ReadServerFile();
Outline
ReadServerFile.java
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
}
}
// end class ReadServerFile
 2002 Prentice Hall, Inc.
All rights reserved.
16
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
17
5.4 Establishing a Simple Server Using
Stream Sockets
• Five steps to create a simple server in Java
– ServerSocket object
• Registers an available port and a maximum number of clients
– Each client connection handled with Server object
• Server blocks until client connects
– Sending and receiving data
• OutputStream to send and InputStream to receive data
• Methods getInputStream and getOutputstream
– Use on Socket object
– Process phase
• Server and Client communicate via streams
– Close streams and connections
 2002 Prentice Hall, Inc. All rights reserved.
18
5.5 Establishing a Simple Client Using
Stream Sockets
• Four steps to create a simple client in Java
– Create a Socket object for the client
– Obtain Socket’s InputStream and Outputstream
– Process information communicated
– Close streams and Socket
 2002 Prentice Hall, Inc. All rights reserved.
19
5.6 Client/Server Interaction with Stream
Socket Connections
• Client/server chat application
– Uses stream sockets as described in last two sections
 2002 Prentice Hall, Inc. All rights reserved.
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//
//
//
//
Fig. 5.4: Server.java
Set up a Server that will receive a connection
from a client, send a string to the client,
and close the connection.
// Java core packages
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
Outline
Server.java
Lines 25-58
// Java extension packages
import javax.swing.*;
public class Server extends JFrame {
private JTextField enterField;
private JTextArea displayArea;
private ObjectOutputStream output;
private ObjectInputStream input;
private ServerSocket server;
private Socket connection;
private int counter = 1;
// set up GUI
public Server()
{
super( "Server" );
Server’s
constructor creates
GUI
Container container = getContentPane();
// create enterField and register listener
enterField = new JTextField();
enterField.setEnabled( false );
 2002 Prentice Hall, Inc.
All rights reserved.
21
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
enterField.addActionListener(
Outline
new ActionListener() {
// send message to client
public void actionPerformed( ActionEvent event )
{
sendData( event.getActionCommand() );
}
}
// end anonymous inner class
Server.java
Call40-43
method
Lines
actionPerformed
when Enter key
pressed
); // end call to addActionListener
container.add( enterField, BorderLayout.NORTH );
// create displayArea
displayArea = new JTextArea();
container.add( new JScrollPane( displayArea ),
BorderLayout.CENTER );
setSize( 300, 150 );
setVisible( true );
}
 2002 Prentice Hall, Inc.
All rights reserved.
22
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// set up and run server
public void runServer()
{
// set up server to receive connections;
// process connections
try {
// Step 1: Create a ServerSocket.
server = new ServerSocket( 5000, 100 );
while ( true ) {
// Step 2: Wait for a connection.
waitForConnection();
// Step 3: Get input and output streams.
getStreams();
// Step 4: Process connection.
processConnection();
// Step 5: Close connection.
closeConnection();
++counter;
}
}
// process EOFException when client closes connection
catch ( EOFException eofException ) {
Call method
System.out.println( "Client terminated
connection" );
closeConnection
}
Method Outline
runServer
sets up server and
processes connection
Server.java
Create
Lines 61-97
ServerSocket at
port 5000
Line
68 with queue
of length 100
Line 73
Call method
waitForConnection
Line 76
to wait for client
connection
Line 79
Call method
Line
82
getStreams
to get
InputStream and
OutputStream
Call method
processConnection
to process all messages
to terminate connection
 2002 Prentice Hall, Inc.
All rights reserved.
23
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// process problems with I/O
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
// wait for connection to arrive, then display connection info
private void waitForConnection() throws IOException
{
displayArea.setText( "Waiting for connection\n" );
Server.java
Method
waitForConnection
Lines 100-110
waits for client
connection
Line
105
// allow server to accept a connection
connection = server.accept();
Method accept
Lines 107-109
waits for connection
displayArea.append( "Connection " + counter +
" received from: " +
connection.getInetAddress().getHostName() );
Lines 113-127
Output name of
computer that
Line 120
connected
}
// get streams to send and receive data
private void getStreams() throws IOException
{
// set up output stream for objects
output = new ObjectOutputStream(
connection.getOutputStream() );
// flush output buffer to send header information
output.flush();
// set up input stream for objects
input = new ObjectInputStream(
connection.getInputStream() );
displayArea.append( "\nGot I/O streams\n" );
}
Outline
Method
getStreams gets
references to
InputStream and
OutputStream of
Socket
Method flush
empties output buffer
and sends header
information
 2002
Prentice Hall, Inc.
All rights reserved.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// process connection with client
private void processConnection() throws IOException
{
// send connection successful message to client
String message = "SERVER>>> Connection successful";
output.writeObject( message );
output.flush();
Method
Outline
processConnection
processes connections
with
clients
Server.java
// enable enterField so server user can send messages
enterField.setEnabled( true );
// process messages sent from client
do {
// read message and display it
try {
message = ( String ) input.readObject();
displayArea.append( "\n" + message );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
// catch problems reading from client
catch ( ClassNotFoundException classNotFoundException ) {
displayArea.append( "\nUnknown object type received" );
}
24
Send connection
Lines 130-157
successful message to
client
Lines 134-135
Loop141-156
until server
Lines
receives terminate
Lines message
145-146
Read String from
Lines 147-148
client and display it
Change cursor
position
} while ( !message.equals( "CLIENT>>> TERMINATE" ) );
}
 2002 Prentice Hall, Inc.
All rights reserved.
25
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// close streams and socket
private void closeConnection() throws IOException
{
displayArea.append( "\nUser terminated connection" );
enterField.setEnabled( false );
output.close();
input.close();
connection.close();
}
// send message to client
private void sendData( String message )
{
// send object to client
try {
output.writeObject( "SERVER>>> " + message );
output.flush();
displayArea.append( "\nSERVER>>>" + message );
}
Outline
Server.java
Method
Lines
160-167
closeConnection
closes streams and
Lines sockets
170-183
Method sendData
sends a message to
the client
// process problems sending object
catch ( IOException ioException ) {
displayArea.append( "\nError writing object" );
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
26
185
186
187
188
189
190
191
192
193
194
195
196
// execute application
public static void main( String args[] )
{
Server application = new Server();
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
application.runServer();
}
}
// end class Server
Outline
Server.java
Method main creates
Lines 186-194
an instance of
Server and calls
method runServer
to run it
 2002 Prentice Hall, Inc.
All rights reserved.
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Fig. 5.5: Client.java
// Set up a Client that will read information sent
// from a Server and display the information.
// Java core packages
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
Outline
Client.java
Lines 24-60
// Java extension packages
import javax.swing.*;
public class Client extends JFrame {
private JTextField enterField;
private JTextArea displayArea;
private ObjectOutputStream output;
private ObjectInputStream input;
private String message = "";
private String chatServer;
private Socket client;
// initialize chatServer and set up GUI
public Client( String host )
{
super( "Client" );
Client’s
constructor creates
GUI
// set server to which this client connects
chatServer = host;
Container container = getContentPane();
// create enterField and register listener
enterField = new JTextField();
enterField.setEnabled( false );
 2002 Prentice Hall, Inc.
All rights reserved.
28
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
enterField.addActionListener(
Outline
new ActionListener() {
// send message to server
public void actionPerformed( ActionEvent event )
{
sendData( event.getActionCommand() );
}
}
// end anonymous inner class
Client.java
Lines Method
42-45
actionPerformed
reads String from
JTextField
); // end call to addActionListener
container.add( enterField, BorderLayout.NORTH );
// create displayArea
displayArea = new JTextArea();
container.add( new JScrollPane( displayArea ),
BorderLayout.CENTER );
setSize( 300, 150 );
setVisible( true );
}
 2002 Prentice Hall, Inc.
All rights reserved.
29
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// connect to server and process messages from server
public void runClient()
{
// connect to server, get streams, process connection
try {
// Step 1: Create a Socket to make connection
connectToServer();
// Step 2: Get the input and output streams
getStreams();
// Step 3: Process connection
processConnection();
// Step 4: Close connection
closeConnection();
}
// server closed connection
catch ( EOFException eofException ) {
System.out.println( "Server terminated connection" );
}
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Outline
Client.java
Method runClient
Lines
63-90
connects
to server
and processes
Line 69
messages
LineCall
72 method
connectToServer
to make
Line
75 connection
LineCall
78 method
getStreams to get
input and output
streams
Call method
processConnection
to handle messages from
server
}
Call method
closeConnection
to close connection
 2002 Prentice Hall, Inc.
All rights reserved.
30
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// get streams to send and receive data
private void getStreams() throws IOException
{
// set up output stream for objects
output = new ObjectOutputStream(
client.getOutputStream() );
// flush output buffer to send header information
output.flush();
// set up input stream for objects
input = new ObjectInputStream(
client.getInputStream() );
Outline
Client.java
Method
Lines
93-106 gets
getStreams
streams to send and
Lines
110-121
receive
data
displayArea.append( "\nGot I/O streams\n" );
}
// connect to server
private void connectToServer() throws IOException
{
displayArea.setText( "Attempting connection\n" );
Method
connectToServer
connects to server
// create Socket to make connection to server
client = new Socket(
InetAddress.getByName( chatServer ), 5000 );
// display connection information
displayArea.append( "Connected to: " +
client.getInetAddress().getHostName() );
}
 2002 Prentice Hall, Inc.
All rights reserved.
31
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// process connection with server
private void processConnection() throws IOException
{
// enable enterField so client user can send messages
enterField.setEnabled( true );
// process messages sent from server
do {
// read message and display it
try {
message = ( String ) input.readObject();
displayArea.append( "\n" + message );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
Outline
Client.java
Method
processConnection
Lines 124-147
processes connection
Line with
135 server
Display
message in
Lines
150-156
JTextArea
// catch problems reading from server
catch ( ClassNotFoundException classNotFoundException ) {
displayArea.append( "\nUnknown object type received" );
}
} while ( !message.equals( "SERVER>>> TERMINATE" ) );
}
// end method process connection
// close streams and socket
private void closeConnection() throws IOException
{
displayArea.append( "\nClosing connection" );
output.close();
input.close();
client.close();
}
Method
closeConnection
closes connection
 2002 Prentice Hall, Inc.
All rights reserved.
32
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// send message to server
private void sendData( String message )
{
// send object to server
try {
output.writeObject( "CLIENT>>> " + message );
output.flush();
displayArea.append( "\nCLIENT>>>" + message );
}
Outline
Client.java
Method sendData
Lines
sends 159-172
data to server
Lines 175-188
// process problems sending object
catch ( IOException ioException ) {
displayArea.append( "\nError writing object" );
}
}
// execute application
public static void main( String args[] )
{
Client application;
Method main creates
a new Client and
calls method
runClient
if ( args.length == 0 )
application = new Client( "127.0.0.1" );
else
application = new Client( args[ 0 ] );
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
application.runClient();
}
}
// end class Client
 2002 Prentice Hall, Inc.
All rights reserved.
33
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
34
5.7 Connectionless Client/Server
Interaction with Datagrams
• Connectionless transmission with datagrams
–
–
–
–
No connection maintained with other computer
Break message into equal sized pieces and send as packets
Message arrive in order, out of order or not at all
Receiver puts messages in order and reads them
 2002 Prentice Hall, Inc. All rights reserved.
35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Fig. 5.6: Server.java
// Set up a Server that will receive packets from a
// client and send packets to a client.
// Java core packages
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
Outline
Server.java
Lines 20-41
Line 32
// Java extension packages
import javax.swing.*;
public class Server extends JFrame {
private JTextArea displayArea;
private DatagramPacket sendPacket, receivePacket;
private DatagramSocket socket;
// set up GUI and DatagramSocket
public Server()
{
super( "Server" );
displayArea = new JTextArea();
getContentPane().add( new JScrollPane( displayArea ),
BorderLayout.CENTER );
setSize( 400, 300 );
setVisible( true );
// create DatagramSocket for sending and receiving packets
try {
socket = new DatagramSocket( 5000 );
}
Constructor creates
GUI
Create
DatagramSocket
at port 5000
 2002 Prentice Hall, Inc.
All rights reserved.
36
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// process problems creating DatagramSocket
catch( SocketException socketException ) {
socketException.printStackTrace();
System.exit( 1 );
}
}
// end Server constructor
// wait for packets to arrive, then display data and echo
// packet to client
public void waitForPackets()
{
// loop forever
while ( true ) {
// receive packet, display contents, echo to client
try {
// set up packet
byte data[] = new byte[ 100 ];
receivePacket =
new DatagramPacket( data, data.length );
// wait for packet
socket.receive( receivePacket );
// process packet
displayPacket();
Outline
Server.java
Method
Lines
45-76
waitForPackets
uses an infinite loop
Lines
to wait54-56
for packets to
arrive
Line 59
Create a
DatagramPacket
to store received
information
Method receive
blocks until a packet
is received
// echo information from packet back to client
sendPacketToClient();
}
 2002 Prentice Hall, Inc.
All rights reserved.
37
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// process problems manipulating packet
catch( IOException ioException ) {
displayArea.append( ioException.toString() + "\n" );
ioException.printStackTrace();
}
}
}
// end while
// end method waitForPackets
// display packet contents
private void displayPacket()
{
displayArea.append( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
Method
"\nHost port: " + receivePacket.getPort() +
sendPacketToClient
"\nLength: " + receivePacket.getLength()
+
"\nContaining:\n\t" +
echoes the packet to the
new String( receivePacket.getData(), 0,
client
receivePacket.getLength() ) );
}
Create packet to be
// echo packet to client
sent
private void sendPacketToClient() throws IOException
{
displayArea.append( "\n\nEcho data to client..." );
// create packet to send
sendPacket = new DatagramPacket( receivePacket.getData(),
receivePacket.getLength(), receivePacket.getAddress(),
receivePacket.getPort() );
// send packet
socket.send( sendPacket );
Method send sends
the pack over the
network
Outline
Server.java
Method
Lines
79-88
displayPacket
appends packet’s
Line contents
82
to
displayArea
Line 83
Method
getAddress
Line
84
returns name of
computer
Line
86 that sent
packet
Lines 91-106
Method getPort
returns the port the
Lines 96-98
packet came through
Line
101
Method
getLength
returns the length of
the message sent
Method getData
returns a byte array
containing the sent
 2002 Prentice
data Hall, Inc.
All rights reserved.
38
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
displayArea.append( "Packet sent\n" );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
// execute application
public static void main( String args[] )
{
Server application = new Server();
Outline
Server.java
Method main creates
Lines 109-117
a new server and
waits for packets
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
application.waitForPackets();
}
}
// end class Server
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Fig. 5.7: Client.java
// Set up a Client that will send packets to a
// server and receive packets from a server.
// Java core packages
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
Outline
Client.java
Lines 21-93
// Java extension packages
import javax.swing.*;
public class Client extends JFrame {
private JTextField enterField;
private JTextArea displayArea;
private DatagramPacket sendPacket, receivePacket;
private DatagramSocket socket;
// set up GUI and DatagramSocket
public Client()
{
super( "Client" );
Constructor sets up
GUI and
DatagramSocket
object
Container container = getContentPane();
enterField = new JTextField( "Type message here" );
 2002 Prentice Hall, Inc.
All rights reserved.
40
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
enterField.addActionListener(
Outline
new ActionListener() {
// create and send a packet
public void actionPerformed( ActionEvent event )
{
// create and send packet
try {
displayArea.append(
"\nSending packet containing: " +
event.getActionCommand() + "\n" );
// get message from textfield and convert to
// array of bytes
String message = event.getActionCommand();
byte data[] = message.getBytes();
// create sendPacket
sendPacket = new DatagramPacket(
data, data.length,
InetAddress.getLocalHost(), 5000 );
// send packet
socket.send( sendPacket );
Client.java
Method
Lines
34-67
actionPerformed
converts a String to
Line
45 array to be
a byte
sent as a datagram
Lines 48-50
Convert the String
Line
to a53byte array
Create the
DatagramPacket
to send
Send the packet with
method send
displayArea.append( "Packet sent\n" );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
 2002 Prentice Hall, Inc.
All rights reserved.
41
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// process problems creating or sending packet
catch ( IOException ioException ) {
displayArea.append(
ioException.toString() + "\n" );
ioException.printStackTrace();
}
}
}
// end actionPerformed
Outline
Client.java
Line 84
// end anonymous inner class
); // end call to addActionListener
container.add( enterField, BorderLayout.NORTH );
displayArea = new JTextArea();
container.add( new JScrollPane( displayArea ),
BorderLayout.CENTER );
setSize( 400, 300 );
setVisible( true );
// create DatagramSocket for sending and receiving packets
try {
socket = new DatagramSocket();
}
Create
DatagramSocket
for sending and
receiving packets
// catch problems creating DatagramSocket
catch( SocketException socketException ) {
socketException.printStackTrace();
System.exit( 1 );
}
}
// end Client constructor
 2002 Prentice Hall, Inc.
All rights reserved.
42
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// wait for packets to arrive from Server,
// then display packet contents
public void waitForPackets()
{
// loop forever
while ( true ) {
// receive packet and display contents
try {
// set up packet
byte data[] = new byte[ 100 ];
receivePacket =
new DatagramPacket( data, data.length );
// wait for packet
socket.receive( receivePacket );
// display packet contents
displayPacket();
}
Outline
Client.java
Method
Lines
97-125
waitForPackets
uses an infinite loop
Line
111for packets
to wait
from server
Line 114
Block until packet
arrives
Display contents of
packet
// process problems receiving or displaying packet
catch( IOException exception ) {
displayArea.append( exception.toString() + "\n" );
exception.printStackTrace();
}
}
}
// end while
// end method waitForPackets
 2002 Prentice Hall, Inc.
All rights reserved.
43
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// display contents of receivePacket
private void displayPacket()
{
displayArea.append( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
"\nHost port: " + receivePacket.getPort() +
"\nLength: " + receivePacket.getLength() +
"\nContaining:\n\t" +
new String( receivePacket.getData(), 0,
receivePacket.getLength() ) );
displayArea.setCaretPosition(
displayArea.getText().length() );
Outline
Client.java
Method
Lines
128-140
displayPacket
displays packet
contents in
JTextArea
}
// execute application
public static void main( String args[] )
{
Client application = new Client();
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
application.waitForPackets();
}
}
// end class Client
 2002 Prentice Hall, Inc.
All rights reserved.
44
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
45
5.8 Client/Server Tic-Tac-Toe Using a
Multithreaded Server
• Multiple threads
– Server uses one thread per player
• Allow each player to play game independently
 2002 Prentice Hall, Inc. All rights reserved.
46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Fig. 5.8: TicTacToeServer.java
// This class maintains a game of Tic-Tac-Toe for two
// client applets.
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
Outline
TicTacToeServer.java
Lines 22-48
// Java extension packages
import javax.swing.*;
public class TicTacToeServer extends JFrame {
private byte board[];
private JTextArea outputArea;
private Player players[];
private ServerSocket server;
private int currentPlayer;
// set up tic-tac-toe server and GUI that displays messages
public TicTacToeServer()
{
super( "Tic-Tac-Toe Server" );
Constructor creates a
ServerSocket
and server GUI
board = new byte[ 9 ];
players = new Player[ 2 ];
currentPlayer = 0;
// set up ServerSocket
try {
server = new ServerSocket( 5000, 2 );
}
 2002 Prentice Hall, Inc.
All rights reserved.
47
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// process problems creating ServerSocket
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
// set up JTextArea to display messages during execution
outputArea = new JTextArea();
getContentPane().add( outputArea, BorderLayout.CENTER );
outputArea.setText( "Server awaiting connections\n" );
setSize( 300, 300 );
setVisible( true );
}
Outline
TicTacToeServer.java
Method
Lines
51-76execute
waits for two
connections to start
Line 59 game
Line 58
Block while waiting
for each player
// wait for two connections so game can be played
public void execute()
{
// wait for each client to connect
for ( int i = 0; i < players.length; i++ ) {
// wait for connection, create Player, start thread
try {
players[ i ] = new Player( server.accept(), i );
players[ i ].start();
}
Call start method
to begin executing
thread
// process problems receiving connection from client
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Player X is suspended until Player O connects.
// Resume player X now.
synchronized ( players[ 0 ] ) {
players[ 0 ].setSuspended( false );
players[ 0 ].notify();
}
}
48
Outline
TicTacToeServer.java
Lines 87-129
// end method execute
// display a message in outputArea
public void display( String message )
{
outputArea.append( message + "\n" );
}
// Determine if a move is valid.
// This method is synchronized because only one move can be
// made at a time.
public synchronized boolean validMove(
int location, int player )
{
boolean moveDone = false;
Method validMove
allows only one move
at a time
// while not current player, must wait for turn
while ( player != currentPlayer ) {
// wait for turn
try {
wait();
}
// catch wait interruptions
catch( InterruptedException interruptedException ) {
interruptedException.printStackTrace();
}
 2002 Prentice Hall, Inc.
All rights reserved.
49
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
Outline
}
// if location not occupied, make move
if ( !isOccupied( location ) ) {
// set move in board array
board[ location ] =
( byte ) ( currentPlayer == 0 ? 'X' : 'O' );
// change current player
currentPlayer = ( currentPlayer + 1 ) % 2;
// let new current player know that move occurred
players[ currentPlayer ].otherPlayerMoved( location );
// tell waiting player to continue
notify();
// tell player that made move that the move was valid
return true;
}
// tell player that made move that the move was not valid
else
return false;
TicTacToeServer.java
Place
a mark
Lines
110-111
Line 117
on the
board
Line 120
Notify
Line
123 player
a move
occurred
Invoke method
notify to tell
waiting player to
continue
Confirm valid move
to player
}
// determine whether location is occupied
public boolean isOccupied( int location )
{
if ( board[ location ] == 'X' || board [ location ] == 'O' )
return true;
else
return false;
}
 2002 Prentice Hall, Inc.
All rights reserved.
50
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// place code in this method to determine whether game over
public boolean gameOver()
{
return false;
}
// execute application
public static void main( String args[] )
{
TicTacToeServer application = new TicTacToeServer();
Outline
TicTacToeServer.java
Method
main
Lines
147-155
creates
an instance of
Lines 167-189
TicTacToeServer
and calls method
execute
application.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
application.execute();
}
// private inner class Player manages each Player as a thread
private class Player extends Thread {
private Socket connection;
private DataInputStream input;
private DataOutputStream output;
private int playerNumber;
private char mark;
protected boolean suspended = true;
The Player
constructor receives a
Socket object and
gets its input and
output streams
// set up Player thread
public Player( Socket socket, int number )
{
playerNumber = number;
// specify player's mark
mark = ( playerNumber == 0 ? 'X' : 'O' );
 2002 Prentice Hall, Inc.
All rights reserved.
51
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
connection = socket;
// obtain streams from Socket
try {
input = new DataInputStream(
connection.getInputStream() );
output = new DataOutputStream(
connection.getOutputStream() );
}
Outline
TicTacToeServer.java
// process problems getting streams
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
}
// send message that other player moved; message contains
// a String followed by an int
public void otherPlayerMoved( int location )
{
// send message indicating move
try {
output.writeUTF( "Opponent moved" );
output.writeInt( location );
}
// process problems sending message
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
52
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// control thread's execution
public void run()
{
// send client message indicating its mark (X or O),
// process messages from client
try {
display( "Player " + ( playerNumber == 0 ?
'X' : 'O' ) + " connected" );
// send player's mark
output.writeChar( mark );
// send message indicating connection
output.writeUTF( "Player " +
( playerNumber == 0 ? "X connected\n" :
"O connected, please wait\n" ) );
// if player X, wait for another player to arrive
if ( mark == 'X' ) {
output.writeUTF( "Waiting for another player" );
Outline
TicTacToeServer.java
Method run controls
information sent and
Lines
213-214by client
received
Lines 208-271
Line 217
Tell client that
client’s
connection is
Lines
230-233
made
Send player’s mark
Suspend each thread
as it starts executing
// wait for player O
try {
synchronized( this ) {
while ( suspended )
wait();
}
}
// process interruptions while waiting
catch ( InterruptedException exception ) {
exception.printStackTrace();
}
 2002 Prentice Hall, Inc.
All rights reserved.
53
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// send message that other player connected and
// player X can make a move
output.writeUTF(
"Other player connected. Your move." );
}
// while game not over
while ( ! gameOver() ) {
// get move location from client
int location = input.readInt();
// check for valid move
if ( validMove( location, playerNumber ) ) {
display( "loc: " + location );
output.writeUTF( "Valid move." );
}
else
output.writeUTF( "Invalid move, try again" );
Outline
TicTacToeServer.java
Lines 248-260
Loop until game is
Line 251 over
Line 254
Read move location
Lines 254-259
Check if valid move
Send message to
client
}
// close connection to client
connection.close();
}
// process problems communicating with client
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
54
273
274
275
276
277
278
279
280
281
// set whether or not thread is suspended
public void setSuspended( boolean status )
{
suspended = status;
}
}
}
Outline
TicTacToeServer.java
// end class Player
// end class TicTacToeServer
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Fig. 5.9: TicTacToeClient.java
// Client for the TicTacToe program
// Java core packages
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
Outline
TicTacToeClient.java
Lines 30-75
// Java extension packages
import javax.swing.*;
// Client class to let a user play Tic-Tac-Toe with
// another user across a network.
public class TicTacToeClient extends JApplet
implements Runnable {
private
private
private
private
private
private
private
private
private
private
JTextField idField;
JTextArea displayArea;
JPanel boardPanel, panel2;
Square board[][], currentSquare;
Socket connection;
DataInputStream input;
DataOutputStream output;
Thread outputThread;
char myMark;
boolean myTurn;
Method init sets up
GUI
// Set up user-interface and board
public void init()
{
Container container = getContentPane();
 2002 Prentice Hall, Inc.
All rights reserved.
56
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// set up JTextArea to display messages to user
displayArea = new JTextArea( 4, 30 );
displayArea.setEditable( false );
container.add( new JScrollPane( displayArea ),
BorderLayout.SOUTH );
Outline
TicTacToeClient.java
// set up panel for squares in board
boardPanel = new JPanel();
boardPanel.setLayout( new GridLayout( 3, 3, 0, 0 ) );
// create board
board = new Square[ 3 ][ 3 ];
// When creating a Square, the location argument to the
// constructor is a value from 0 to 8 indicating the
// position of the Square on the board. Values 0, 1,
// and 2 are the first row, values 3, 4, and 5 are the
// second row. Values 6, 7, and 8 are the third row.
for ( int row = 0; row < board.length; row++ ) {
for ( int column = 0;
column < board[ row ].length; column++ ) {
// create Square
board[ row ][ column ] =
new Square( ' ', row * 3 + column );
boardPanel.add( board[ row ][ column ] );
}
}
// textfield to display player's mark
idField = new JTextField();
idField.setEditable( false );
 2002 Prentice Hall, Inc.
All rights reserved.
57
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
container.add( idField, BorderLayout.NORTH );
// set up panel to contain boardPanel (for layout purposes)
panel2 = new JPanel();
panel2.add( boardPanel, BorderLayout.CENTER );
container.add( panel2, BorderLayout.CENTER );
}
// Make connection to server and get associated streams.
// Start separate thread to allow this applet to
// continually update its output in text area display.
public void start()
{
// connect to server, get streams and start outputThread
try {
Outline
TicTacToeClient.java
Method
Lines
80-104 start
opens a connection to
server and gets input
and output streams
// make connection
connection = new Socket(
InetAddress.getByName( "127.0.0.1" ), 5000 );
// get streams
input = new DataInputStream(
connection.getInputStream() );
output = new DataOutputStream(
connection.getOutputStream() );
}
// catch problems setting up connection and streams
catch ( IOException ioException ) {
ioException.printStackTrace();
}
 2002 Prentice Hall, Inc.
All rights reserved.
58
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
Outline
// create and start output thread
outputThread = new Thread( this );
outputThread.start();
}
TicTacToeClient.java
// control thread that allows continuous update of the
// text area displayArea
public void run()
{
// get player's mark (X or O)
try {
myMark = input.readChar();
idField.setText( "You are player \"" + myMark + "\"" );
myTurn = ( myMark == 'X' ? true : false );
}
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
// receive messages sent to client and output them
while ( true ) {
// read message from server and process message
try {
String message = input.readUTF();
processMessage( message );
}
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
Create
Lines
102-103
outputThread
and
call method
Lines
108-137
start
Line 112
Method run controls
the separate thread of
Lines 127
execution
Lines 123-135
Read mark character
from server
Loop continually
Read and process
messages from server
 2002 Prentice Hall, Inc.
All rights reserved.
59
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
}
// end method run
// process messages received by client
public void processMessage( String message )
{
// valid move occurred
if ( message.equals( "Valid move." ) ) {
displayArea.append( "Valid move, please wait.\n" );
// set mark in square from event-dispatch thread
SwingUtilities.invokeLater(
new Runnable() {
public void run()
{
currentSquare.setMark( myMark );
}
Outline
TicTacToeClient.java
Method
Lines
140-211
processMessage
processes
Lines
143-159messages
received by client
Lines 162-165
If valid move, write
message and set mark
in square
Lines 168-195
If invalid move,
display message
}
); // end call to invokeLater
}
If opponent moves,
set mark in square
// invalid move occurred
else if ( message.equals( "Invalid move, try again" ) ) {
displayArea.append( message + "\n" );
myTurn = true;
}
// opponent moved
else if ( message.equals( "Opponent moved" ) ) {
 2002 Prentice Hall, Inc.
All rights reserved.
60
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// get move location and update board
try {
final int location = input.readInt();
// set mark in square from event-dispatch thread
SwingUtilities.invokeLater(
Outline
TicTacToeClient.java
new Runnable() {
public void run()
{
int row = location / 3;
int column = location % 3;
board[ row ][ column ].setMark(
( myMark == 'X' ? 'O' : 'X' ) );
displayArea.append(
"Opponent moved. Your turn.\n" );
}
}
); // end call to invokeLater
myTurn = true;
}
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
61
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
Outline
// simply display message
else
displayArea.append( message + "\n" );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
TicTacToeClient.java
If any other message,
display message
Line 206
// end method processMessage
// send message to server indicating clicked square
public void sendClickedSquare( int location )
{
if ( myTurn ) {
// send location to server
try {
output.writeInt( location );
myTurn = false;
}
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
}
// set current Square
public void setCurrentSquare( Square square )
{
currentSquare = square;
}
 2002 Prentice Hall, Inc.
All rights reserved.
62
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// private class for the sqaures on the board
private class Square extends JPanel {
private char mark;
private int location;
Outline
TicTacToeClient.java
public Square( char squareMark, int squareLocation )
{
mark = squareMark;
location = squareLocation;
addMouseListener(
new MouseAdapter() {
public void mouseReleased( MouseEvent e )
{
setCurrentSquare( Square.this );
sendClickedSquare( getSquareLocation() );
}
}
// end anonymous inner class
); // end call to addMouseListener
}
// end Square constructor
// return preferred size of Square
public Dimension getPreferredSize()
{
return new Dimension( 30, 30 );
}
 2002 Prentice Hall, Inc.
All rights reserved.
63
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
// return minimum size of Square
public Dimension getMinimumSize()
{
return getPreferredSize();
}
Outline
TicTacToeClient.java
// set mark for Square
public void setMark( char newMark )
{
mark = newMark;
repaint();
}
// return Square location
public int getSquareLocation()
{
return location;
}
// draw Square
public void paintComponent( Graphics g )
{
super.paintComponent( g );
g.drawRect( 0, 0, 29, 29 );
g.drawString( String.valueOf( mark ), 11, 20 );
}
}
}
// end class Square
// end class TicTacToeClient
 2002 Prentice Hall, Inc.
All rights reserved.
64
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
65
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
66
5.9 Security and the Network
• By default, applets cannot perform file processing
• Applets often limited in machine access
• Java Security API
– Applets given more privileges if from trusted source
 2002 Prentice Hall, Inc. All rights reserved.
67
5.10 DeitelMessenger Chat Server and
Client
• Chat rooms
– Each user can post a message and read all other messages
– Multicast
• Send packets to groups of clients
 2002 Prentice Hall, Inc. All rights reserved.
68
5.10.1 DeitelMessengerServer and
Supporting Classes
• DeitelMessengerServer
– Online chat system
– Classes:
• DeitelMessengerServer
– Clients connect to this server
• Interface SocketMessengerConstants
– Defines constants for port numbers
• Interface MessageListener
– Defines method for receiving new chat messages
• Class ReceivingThread
– Separate thread listens for messages from clients
• Class MulticastSendingThread
– Separate thread delivers outgoing messages to clients
 2002 Prentice Hall, Inc. All rights reserved.
69
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// DeitelMessengerServer.java
// DeitelMessengerServer is a multi-threaded, socket- and
// packet-based chat server.
package com.deitel.messenger.sockets.server;
// Java core packages
import java.util.*;
import java.net.*;
import java.io.*;
// Deitel packages
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
public class DeitelMessengerServer implements MessageListener,
SocketMessengerConstants {
// start chat server
public void startServer()
{
// create server and manage new clients
try {
Outline
DeitelMessenger
Server.java
Method
Lines 19-54
startServer
launches the chat
Lines 25-26
server
Create
ServerSocket to
accept incoming
connections
// create ServerSocket for incoming connections
ServerSocket serverSocket =
new ServerSocket( SERVER_PORT, 100 );
System.out.println( "Server listening on port " +
SERVER_PORT + " ..." );
 2002 Prentice Hall, Inc.
All rights reserved.
70
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// listen for clients constantly
while ( true ) {
// accept new client connection
Socket clientSocket = serverSocket.accept();
// create new ReceivingThread for receiving
// messages from client
new ReceivingThread( this, clientSocket ).start();
// print connection information
System.out.println( "Connection received from: " +
clientSocket.getInetAddress() );
Listen Outline
continuously
for new clients
DeitelMessenger
Invoke method
Server.java
accept to wait for
and accept
Lines
32-45 a new
client connection
Line 35
Create and start a new
ReceivingThread
Line 39
} // end while
} // end try
// handle exception creating server and connecting clients
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end method startServer
 2002 Prentice Hall, Inc.
All rights reserved.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
71
Method
// when new message is received, broadcast message to clients
Outline
messageReceived
public void messageReceived( String from, String message )
{
broadcasts new
// create String containing entire message
messages to clients
DeitelMessenger
String completeMessage = from + MESSAGE_SEPARATOR + message;
Server.java
// create and start MulticastSendingThread to broadcast
Concatenate from
// new messages to all clients
String
Lines
57-66 and
new MulticastSendingThread(
message
completeMessage.getBytes() ).start();
}
Lines 64-65
Create and start new
// start the server
MulticastSendingThread
public static void main ( String args[] )
Lines 69-72
{
to send messages to all clients
new DeitelMessengerServer().startServer();
}
}
Server listening on port 5000 ...
Connection received from: SEANSANTRY/XXX.XXX.XXX.XXX
Connection received from: PJD/XXX.XXX.XXX.XXX
Method main creates a new
DeitelMessengerServer
and starts the server
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
72
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// SocketMessengerConstants.java
// SocketMessengerConstants defines constants for the port numbers
// and multicast address in DeitelMessenger
package com.deitel.messenger.sockets;
public interface SocketMessengerConstants {
// address for multicast datagrams
public static final String MULTICAST_ADDRESS = "230.0.0.1";
// port for listening for multicast datagrams
public static final int MULTICAST_LISTENING_PORT = 5555;
// port for sending multicast datagrams
public static final int MULTICAST_SENDING_PORT = 5554;
// port for Socket connections to DeitelMessengerServer
public static final int SERVER_PORT = 5000;
// String that indicates disconnect
public static final String DISCONNECT_STRING = "DISCONNECT";
// String that separates the user name from the message body
public static final String MESSAGE_SEPARATOR = ">>>";
// message size (in bytes)
public static final int MESSAGE_SIZE = 512;
}
Outline
SocketMessengerC
onstants.java
Address
to send
Line
9
multicast datagrams
Line
Port12listening for
multicast datagrams
Line 15
Port for sending
multicast
Line
18 datagrams
Port for socket
Line
21
connections
to server
that
LineString
24
indicates disconnect
Line 27
String that
separates user name
and message
Maximum message
size in bytes
 2002 Prentice Hall, Inc.
All rights reserved.
73
1
2
3
4
5
6
7
8
9
10
// MessageListener.java
// MessageListener is an interface for classes that wish to
// receive new chat messages.
package com.deitel.messenger;
public interface MessageListener {
// receive new chat message
public void messageReceived( String from, String message );
}
Outline
MessengerListene
r.java
Method
Line 9
messageReceived
allows an
implementing class to
receive messages
 2002 Prentice Hall, Inc.
All rights reserved.
74
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// ReceivingThread.java
// ReceivingThread is a Thread that listens for messages
// from a particular client and delivers messages to a
// MessageListener.
package com.deitel.messenger.sockets.server;
// Java core packages
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
// Deitel packages
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
Outline
ReceivingThread.
java.
Line 28
Line 31
public class ReceivingThread extends Thread implements
SocketMessengerConstants {
private BufferedReader input;
private MessageListener messageListener;
private boolean keepListening = true;
// ReceivingThread constructor
public ReceivingThread( MessageListener listener,
Socket clientSocket )
{
// invoke superclass constructor to name Thread
super( "ReceivingThread: " + clientSocket );
// set listener to which new messages should be sent
messageListener = listener;
Invoke Thread
constructor to provide
unique name for each
ReceivingThread
Set MessageListener to
which ReceivingThread
should deliver new messages
 2002 Prentice Hall, Inc.
All rights reserved.
75
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// set timeout for reading from clientSocket and create
// BufferedReader for reading incoming messages
try {
clientSocket.setSoTimeout( 5000 );
input = new BufferedReader( new InputStreamReader(
clientSocket.getInputStream() ) );
}
// handle exception creating BufferedReader
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Outline
ReceivingThread.
java (Part 2).
Create BufferedReader
Lines 38-39
to read messages from client
Line 55
Line 59
} // end ReceivingThread constructor
// listen for new messages and deliver them to MessageListener
public void run()
{
String message;
// listen for messages until stopped
while ( keepListening ) {
// read message from BufferedReader
try {
message = input.readLine();
}
Listen for messages, as long as
keepListening is true
Read line of data from client
// handle exception if read times out
catch ( InterruptedIOException interruptedIOException ) {
// continue to next iteration to keep listening
continue;
}
 2002 Prentice Hall, Inc.
All rights reserved.
76
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// handle exception reading message
catch ( IOException ioException ) {
ioException.printStackTrace();
break;
}
// ensure non-null message
if ( message != null ) {
Outline
ReceivingThread.
Upon receiving
message,
java (Part
3).
separate message into two
tokens
delimited
Lines
80-90by
Message_SEPARATOR
// tokenize message to retrieve user name
// and message body
StringTokenizer tokenizer =
new StringTokenizer( message, MESSAGE_SEPARATOR );
// ignore messages that do not contain a user
// name and message body
if ( tokenizer.countTokens() == 2 ) {
// send message to MessageListener
messageListener.messageReceived(
tokenizer.nextToken(),
// user name
tokenizer.nextToken() ); // message body
}
 2002 Prentice Hall, Inc.
All rights reserved.
77
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
Outline
else
// if disconnect message received, stop listening
if ( message.equalsIgnoreCase( MESSAGE_SEPARATOR +
DISCONNECT_STRING ) ) {
ReceivingThread.
java (Part 4).
stopListening();
}
}
// end if
} // end while
Determine whether
Lines 96-97
message indicates that user
wishes to leave chat room
Lines 119-122
// close BufferedReader (also closes Socket)
try {
input.close();
}
// handle exception closing BufferedReader
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end method run
// stop listening for incoming messages
public void stopListening()
{
keepListening = false;
}
Method stopListening terminates
while loop in method run
}
 2002 Prentice Hall, Inc.
All rights reserved.
78
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// MulticastSendingThread.java
// MulticastSendingThread is a Thread that broadcasts a chat
// message using a multicast datagram.
package com.deitel.messenger.sockets.server;
// Java core packages
import java.io.*;
import java.net.*;
// Deitel packages
import com.deitel.messenger.sockets.*;
Outline
MulticastSending
Thread.java
Extend Thread to enable
Line 13 to send
DeitelMessengerServer
multicast messages in a separate thread
Line 17
public class MulticastSendingThread extends Thread
implements SocketMessengerConstants {
// message data
private byte[] messageBytes;
byte array to contain message data
// MulticastSendingThread constructor
public MulticastSendingThread( byte[] bytes )
{
// invoke superclass constructor to name Thread
super( "MulticastSendingThread" );
messageBytes = bytes;
}
 2002 Prentice Hall, Inc.
All rights reserved.
79
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Outline
// deliver message to MULTICAST_ADDRESS over DatagramSocket
public void run()
{
Method run delivers
// deliver message
message to multicast MulticastSending
address
try {
// create DatagramSocket for sending message
DatagramSocket socket =
new DatagramSocket( MULTICAST_SENDING_PORT );
// use InetAddress reserved for multicast group
InetAddress group = InetAddress.getByName(
MULTICAST_ADDRESS );
// create DatagramPacket containing message
DatagramPacket packet = new DatagramPacket(
messageBytes, messageBytes.length, group,
MULTICAST_LISTENING_PORT );
// send packet to multicast group and close socket
socket.send( packet );
socket.close();
Thread.java
Create DatagramSocket
for
(Part 2).
delivering DatagramPackets
via
multicast
Lines
29-57
Specify multicast
address
Lines 35-36
Lines 39-40
43-48
Create Lines
DatagramPacket
and send it to clients
}
// handle exception delivering message
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end method run
}
 2002 Prentice Hall, Inc.
All rights reserved.
80
5.10.2 DeitelMessenger Client and
Supporting Classes
• DeitelMessengerServer client
– Consists of five components
• Interface MessageManager
• Class that implements interface MessageManager
– Manages communication with server
• Thread subclass
– Listens for messages at server’s multicast address
• Another Thread subclass
– Sends messages from client to server
• JFrame subclass
– Provides client GUI
 2002 Prentice Hall, Inc. All rights reserved.
81
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Outline
// MessageManager.java
// MessageManager is an interface for objects capable of Connects
managing MessageManager to
// communications with a message server.
DeitelMessengerServer and
package com.deitel.messenger;
public interface MessageManager {
MessageManager.j
routes incoming
messages to
ava
appropriate MessageListener
// connect to message server and route incoming messages
// to given MessageListener
public void connect( MessageListener listener );
// disconnect from message server and stop routing
// incoming messages to given MessageListener
public void disconnect( MessageListener listener );
Line 10
Disconnects MessageManager
Line 14
from DeitelMessengerServer
and stops delivering messages to
Line 17
MessageListener
// send message to message server
public void sendMessage( String from, String message );
}
Sends new message to
DeitelMessengerServer
 2002 Prentice Hall, Inc.
All rights reserved.
82
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// SocketMessageManager.java
// SocketMessageManager is a MessageManager implementation for
// communicating with a DeitelMessengerServer using Sockets
// and MulticastSockets.
package com.deitel.messenger.sockets.client;
// Java core packages
import java.util.*;
import java.net.*;
import java.io.*;
Outline
SocketMessageMan
age.java
Line 20
Line 26
// Deitel packages
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
Line 29
public class SocketMessageManager implements MessageManager,
SocketMessengerConstants {
// Socket for outgoing messages
private Socket clientSocket;
Socket for connecting and sending
messages to DeitelMessengerServer
// DeitelMessengerServer address
private String serverAddress;
// Thread for receiving multicast messages
private PacketReceivingThread receivingThread;
// flag indicating connection status
private boolean connected = false;
// SocketMessageManager constructor
public SocketMessageManager( String address )
{
serverAddress = address;
}
Thread listens for
incoming messages
Indicates whether
SocketMessageManager is connected
to DeitelMessengerServer
 2002 Prentice Hall, Inc.
All rights reserved.
83
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
// connect to server and send messages to given MessageListener
public void connect( MessageListener listener )
{
Connects SocketMessageManager
SocketMessageMan
// if already connected, return immediately
to DeitelMessengerServer
age.java (Part(if
2).
if ( connected )
not previously connected)
return;
// open Socket connection to DeitelMessengerServer
try {
clientSocket = new Socket(
InetAddress.getByName( serverAddress ), SERVER_PORT );
// create Thread for receiving incoming messages
receivingThread = new PacketReceivingThread( listener );
receivingThread.start();
// update connected flag
connected = true;
Lines
Create38-63
Socket to
communicate with
Lines
46-47
DeitelMessengerServer
Lines 50-51
Lines 66-104
Start Thread that listens
for incoming messages
} // end try
// handle exception connecting to server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Terminates SocketMessageManager
connection to DeitelMessengerServer
} // end method connect
// disconnect from server and unregister given MessageListener
public void disconnect( MessageListener listener )
{
// if not connected, return immediately
if ( !connected )
return;
 2002 Prentice Hall, Inc.
All rights reserved.
84
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// stop listening thread and disconnect from server
try {
// notify server that client is disconnecting
Thread disconnectThread = new SendingThread(
clientSocket, "", DISCONNECT_STRING );
disconnectThread.start();
Outline
Start Thread that informs
DeitelMessengerServer
SocketMessageMan
of disconnection
age.java (Part 3).
// wait 10 seconds for disconnect message to be sent
disconnectThread.join( 10000 );
Lines 76-77
Line 87
// stop receivingThread and remove given MessageListener
receivingThread.stopListening();
// close outgoing Socket
clientSocket.close();
Disconnection by closing Socket
} // end try
// handle exception disconnecting from server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
// handle exception joining disconnectThread
catch ( InterruptedException interruptedException ) {
interruptedException.printStackTrace();
}
// update connected flag
connected = false;
} // end method disconnect
 2002 Prentice Hall, Inc.
All rights reserved.
85
106
107
108
109
110
111
112
113
114
115
116
// send message to server
public void sendMessage( String from, String message )
{
// if not connected, return immediately
if ( !connected )
return;
// create and start new SendingThread to deliver message
new SendingThread( clientSocket, from, message).start();
Outline
SocketMessageMan
age.java (Part 4).
Line 114
}
}
Send message to
DeitelMessengerServer
 2002 Prentice Hall, Inc.
All rights reserved.
86
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// SendingThread.java
// SendingThread sends a message to the chat server in a
// separate Thread.
package com.deitel.messenger.sockets.client;
// Java core packages
import java.io.*;
import java.net.*;
// Deitel packages
import com.deitel.messenger.sockets.*;
public class SendingThread extends Thread
implements SocketMessengerConstants {
Outline
SendingThread.ja
va
Line 13
Line 30
Delivers outgoing messages to
DeitelMessengerServer
// Socket over which to send message
private Socket clientSocket;
private String messageToSend;
// SendingThread constructor
public SendingThread( Socket socket, String userName,
String message )
{
// invoke superclass constructor to name Thread
super( "SendingThread: " + socket );
clientSocket = socket;
// build the message to be sent
messageToSend = userName + MESSAGE_SEPARATOR + message;
}
Create message
 2002 Prentice Hall, Inc.
All rights reserved.
87
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// send message and exit Thread
public void run()
{
// send message and flush PrintWriter
try {
PrintWriter writer =
new PrintWriter( clientSocket.getOutputStream() );
writer.println( messageToSend );
writer.flush();
Use method
}
// handle exception sending message
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Outline
SendingThread.ja
va (Part 2).
Line 40
println of class
PrintWriter to send message
to DeitelMessengerServer
} // end method run
}
 2002 Prentice Hall, Inc.
All rights reserved.
88
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// PacketReceivingThread.java
// PacketReceivingThread listens for DatagramPackets containing
// messages from a DeitelMessengerServer.
package com.deitel.messenger.sockets.client;
// Java core packages
import java.io.*;
import java.net.*;
import java.util.*;
// Deitel packages
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
public class PacketReceivingThread extends Thread
implements SocketMessengerConstants {
Line 22
Declare MessageListener
to
receive incoming messages
Line 25
// MulticastSocket for receiving broadcast messages
private MulticastSocket multicastSocket;
// flag for terminating PacketReceivingThread
private boolean keepListening = true;
PacketReceivingT
hread.java
Line 15
Enables SocketMessageManager
to listen for incoming messages
Line 19
// MessageListener to whom messages should be delivered
private MessageListener messageListener;
// InetAddress of group for messages
private InetAddress multicastGroup;
Outline
Declare
MulticastSocket
for receiving multicast
DatagramPackets
Multicast address to which
DeitelMessengerServer
posts chat messages
// PacketReceivingThread constructor
public PacketReceivingThread( MessageListener listener )
{
// invoke superclass constructor to name Thread
super( "PacketReceivingThread" );
 2002 Prentice Hall, Inc.
All rights reserved.
89
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// set MessageListener
messageListener = listener;
// connect MulticastSocket
try {
multicastSocket =
new MulticastSocket(
Outline
MulticastSocket listens
for
incoming chat messages on port
to multicast address MULTICAST_LISTENING_PORT
and port
PacketReceivingT
hread.java
MULTICAST_LISTENING_PORT );
(Part 2).
InetAddress object to which
Lines 41-42
DeitelMessengerServer
multicasts chat messages
Lines 44-45
multicastGroup =
InetAddress.getByName( MULTICAST_ADDRESS );
// join multicast group to receive messages
multicastSocket.joinGroup( multicastGroup );
MulticastSocket
Line 48
to receive messages sent to
MULTICAST_ADDRESS
Lines 62-131
// set 5 second time-out when waiting for new packets
Register
multicastSocket.setSoTimeout( 5000 );
}
// handle exception connecting to multicast address
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Line 68
} // end PacketReceivingThread constructor
// listen for messages from multicast group
public void run()
{
// listen for messages until stopped
while ( keepListening ) {
// create buffer for incoming message
byte[] buffer = new byte[ MESSAGE_SIZE ];
Method run listens for
incoming multicast messages
Create byte array for
storing DatagramPacket
 2002 Prentice Hall, Inc.
All rights reserved.
90
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// create DatagramPacket for incoming message
DatagramPacket packet = new DatagramPacket( buffer,
MESSAGE_SIZE );
// receive new DatagramPacket (blocking call)
try {
multicastSocket.receive( packet );
}
Outline
Create DatagramPacket
PacketReceivingT
for storing message
hread.java
(Part 3).
Read incoming
packet
from multicast address
Lines 71-72
// handle exception when receive times out
catch ( InterruptedIOException interruptedIOException ) {
Line 76
// continue to next iteration to keep listening
continue;
}
// handle exception reading packet from multicast
catch ( IOException ioException ) {
ioException.printStackTrace();
break;
}
MethodLines
receive
throws this
80-84
exception if 5000 ms. pass
group
withoutLine
receipt
93 of a packet
// put message data in a String
String message = new String( packet.getData() );
Retrieve message data
// ensure non-null message
if ( message != null ) {
// trim extra whitespace from end of message
message = message.trim();
// tokenize message to retrieve user name
// and message body
StringTokenizer tokenizer =
new StringTokenizer( message, MESSAGE_SEPARATOR );
 2002 Prentice Hall, Inc.
All rights reserved.
91
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// ignore messages that do not contain a user
// name and message body
if ( tokenizer.countTokens() == 2 ) {
// send message to MessageListener
messageListener.messageReceived(
tokenizer.nextToken(),
// user name
tokenizer.nextToken() ); // message body
}
} // end if
} // end while
Outline
PacketReceivingT
hread.java
(Part 4).
Lines 111-113
After parsing message, deliver message to
PacketReceivingThread’s
Line 122
MessageListener
// leave multicast group and close MulticastSocket
try {
multicastSocket.leaveGroup( multicastGroup );
multicastSocket.close();
}
Stop receiving messages
from multicast address
// handle exception reading packet from multicast group
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end method run
// stop listening for new messages
public void stopListening()
{
// terminate Thread
keepListening = false;
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
92
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ClientGUI.java
// ClientGUI provides a user interface for sending and receiving
// messages to and from the DeitelMessengerServer.
package com.deitel.messenger;
// Java core packages
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
// Java standard extensions
import javax.swing.*;
import javax.swing.border.*;
public class ClientGUI extends JFrame {
Outline
ClientGUI.java
Line 16
Lines 22-23
Lines 26-29
Create GUI for user to send
and receive chat messages
// JMenu for connecting/disconnecting server
private JMenu serverMenu;
// JTextAreas for displaying and inputting messages
private JTextArea messageArea;
private JTextArea inputArea;
JTextAreas for displaying
and entering messages
// JButtons and JMenuItems for connecting and disconnecting
private JButton connectButton;
private JMenuItem connectMenuItem;
Controls allowing client to connect
private JButton disconnectButton;
and disconnect from server
private JMenuItem disconnectMenuItem;
// JButton for sending messages
private JButton sendButton;
// JLabel for displaying connection status
private JLabel statusBar;
 2002 Prentice Hall, Inc.
All rights reserved.
93
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// userName to add to outgoing messages
private String userName;
// MessageManager for communicating with server
private MessageManager messageManager;
// MessageListener for receiving incoming messages
private MessageListener messageListener;
// ClientGUI constructor
public ClientGUI( MessageManager manager )
{
super( "Deitel Messenger" );
Outline
ClientGUI.java
MessageManager handles
(Part 2).
communication with chat server
Line 41
MessageListener
receives Line
incoming
44 messages
from MessageManager
// set the MessageManager
messageManager = manager;
// create MyMessageListener for receiving messages
messageListener = new MyMessageListener();
// create File JMenu
serverMenu = new JMenu ( "Server" );
serverMenu.setMnemonic( 'S' );
JMenuBar menuBar = new JMenuBar();
menuBar.add( serverMenu );
setJMenuBar( menuBar );
// create ImageIcon for connect buttons
Icon connectIcon = new ImageIcon(
getClass().getResource( "images/Connect.gif" ) );
 2002 Prentice Hall, Inc.
All rights reserved.
94
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// create connectButton and connectMenuItem
connectButton = new JButton( "Connect", connectIcon );
connectMenuItem = new JMenuItem( "Connect", connectIcon );
connectMenuItem.setMnemonic( 'C' );
// create ConnectListener for connect buttons
ActionListener connectListener = new ConnectListener();
connectButton.addActionListener( connectListener );
connectMenuItem.addActionListener( connectListener );
Outline
ClientGUI.java
(Part 3).
Lines 69-101
// create ImageIcon for disconnect buttons
Icon disconnectIcon = new ImageIcon(
getClass().getResource( "images/Disconnect.gif" ) );
// create disconnectButton and disconnectMenuItem
disconnectButton = new JButton( "Disconnect",
disconnectIcon );
disconnectMenuItem = new JMenuItem( "Disconnect",
disconnectIcon );
disconnectMenuItem.setMnemonic( 'D' );
Create controls allowing
user to connect the client
to, and disconnect the
client from, the chat server
// disable disconnect buttons
disconnectButton.setEnabled( false );
disconnectMenuItem.setEnabled( false );
// create DisconnectListener for disconnect buttons
ActionListener disconnectListener =
new DisconnectListener();
disconnectButton.addActionListener( disconnectListener );
disconnectMenuItem.addActionListener( disconnectListener );
// add connect and disconnect JMenuItems to fileMenu
serverMenu.add( connectMenuItem );
serverMenu.add( disconnectMenuItem );
 2002 Prentice Hall, Inc.
All rights reserved.
95
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// add connect and disconnect JButtons to buttonPanel
JPanel buttonPanel = new JPanel();
buttonPanel.add( connectButton );
buttonPanel.add( disconnectButton );
// create JTextArea for displaying messages
messageArea = new JTextArea();
// disable editing and wrap words at end of line
messageArea.setEditable( false );
messageArea.setWrapStyleWord( true );
messageArea.setLineWrap( true );
// put messageArea in JScrollPane to enable scrolling
JPanel messagePanel = new JPanel();
messagePanel.setLayout( new BorderLayout( 10, 10 ) );
messagePanel.add( new JScrollPane( messageArea ),
BorderLayout.CENTER );
Outline
ClientGUI.java
(Part 4).
Lines 109 and 123
Instantiate JTextAreas
for displaying and
entering messages
// create JTextArea for entering new messages
inputArea = new JTextArea( 4, 20 );
inputArea.setWrapStyleWord( true );
inputArea.setLineWrap( true );
inputArea.setEditable( false );
// create Icon for sendButton
Icon sendIcon = new ImageIcon(
getClass().getResource( "images/Send.gif" ) );
// create sendButton and disable it
sendButton = new JButton( "Send", sendIcon );
sendButton.setEnabled( false );
 2002 Prentice Hall, Inc.
All rights reserved.
96
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
Outline
// create ActionListener for sendButton
sendButton.addActionListener(
new ActionListener() {
// send new message when user activates sendButton
public void actionPerformed( ActionEvent event )
{
messageManager.sendMessage( userName,
inputArea.getText());
// clear inputArea
inputArea.setText( "" );
}
} // end ActionListener
ClientGUI.java
(Part 5).
Lines 143-144
Send user’s name and inputArea’s
text to DeitelMessengerServer
as a chat message
);
// lay out inputArea and sendButton in BoxLayout and
// add Box to messagePanel
Box box = new Box( BoxLayout.X_AXIS );
box.add( new JScrollPane( inputArea ) );
box.add( sendButton );
messagePanel.add( box, BorderLayout.SOUTH );
// create JLabel for statusBar with a recessed border
statusBar = new JLabel( "Not Connected" );
statusBar.setBorder(
new BevelBorder( BevelBorder.LOWERED ) );
// lay out components in JFrame
Container container = getContentPane();
container.add( buttonPanel, BorderLayout.NORTH );
container.add( messagePanel, BorderLayout.CENTER );
container.add( statusBar, BorderLayout.SOUTH );
 2002 Prentice Hall, Inc.
All rights reserved.
97
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
Outline
// add WindowListener to disconnect when user quits
addWindowListener (
new WindowAdapter () {
ClientGUI.java
(Part 6).
// disconnect from server and exit application
public void windowClosing ( WindowEvent event )
{
messageManager.disconnect( messageListener );
System.exit( 0 );
}
}
);
} // end ClientGUI constructor
Lines 175-178
Line
194
Disconnect from
chat
server when
user exits client application
// ConnectListener listens for user requests to connect to
// DeitelMessengerSever
private class ConnectListener implements ActionListener {
// connect to server and enable/disable GUI components
public void actionPerformed( ActionEvent event )
{
// connect to server and route messages to
// messageListener
messageManager.connect( messageListener );
When user accesses Connect
menu, connect to chat server
// prompt for userName
userName = JOptionPane.showInputDialog(
ClientGUI.this, "Enter user name:" );
// clear messageArea
messageArea.setText( "" );
 2002 Prentice Hall, Inc.
All rights reserved.
98
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
Outline
// update GUI components
connectButton.setEnabled( false );
connectMenuItem.setEnabled( false );
disconnectButton.setEnabled( true );
disconnectMenuItem.setEnabled( true );
sendButton.setEnabled( true );
inputArea.setEditable( true );
inputArea.requestFocus();
statusBar.setText( "Connected: " + userName );
ClientGUI.java
(Part 7).
Line 225
}
} // end ConnectListener inner class
// DisconnectListener listens for user requests to disconnect
// from DeitelMessengerServer
private class DisconnectListener implements ActionListener {
// disconnect from server and enable/disable GUI components
public void actionPerformed( ActionEvent event )
{
// disconnect from server and stop routing messages
// to messageListener
messageManager.disconnect( messageListener );
// update GUI componets
sendButton.setEnabled( false );
disconnectButton.setEnabled( false );
disconnectMenuItem.setEnabled( false );
inputArea.setEditable( false );
connectButton.setEnabled( true );
connectMenuItem.setEnabled( true );
statusBar.setText( "Not Connected" );
When user accesses Disconnect
menu, disconnect from chat server
}
} // end DisconnectListener inner class
 2002 Prentice Hall, Inc.
All rights reserved.
99
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// MyMessageListener listens for new messages from the
// MessageManager and displays the messages in messageArea
// using a MessageDisplayer.
private class MyMessageListener implements MessageListener {
// when received, display new messages in messageArea
public void messageReceived( String from, String message )
{
// append message using MessageDisplayer and
// invokeLater, ensuring thread-safe access messageArea
SwingUtilities.invokeLater(
new MessageDisplayer( from, message ) );
} // end method messageReceived
}
// end MyMessageListener inner class
Outline
ClientGUI.java
(Part 8).
Lines 244-254
Lines 260-285
Display message when
MessageListener detects that
message was received
// MessageDisplayer displays a new messaage by
// appending the message to the messageArea JTextArea. This
// Runnable object should be executed only on the Event
// thread, because it modifies a live Swing component.
private class MessageDisplayer implements Runnable {
private String fromUser;
private String messageBody;
MessageDisplayer displays
message in JTextArea
// MessageDisplayer constructor
public MessageDisplayer( String from, String body )
{
fromUser = from;
messageBody = body;
}
 2002 Prentice Hall, Inc.
All rights reserved.
100
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
// display new message in messageArea
public void run()
{
// append new message
messageArea.append( "\n" + fromUser + "> " +
messageBody );
Outline
ClientGUI.java
(Part 9).
// move caret to end of messageArea to ensure new
// message is visible on screen
messageArea.setCaretPosition(
messageArea.getText().length() );
}
} // end MessageDisplayer inner class
}
 2002 Prentice Hall, Inc.
All rights reserved.
101
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Outline
// DeitelMessenger.java
// DeitelMessenger is a chat application that uses a ClientGUI
// and SocketMessageManager to communicate with
// DeitelMessengerServer.
package com.deitel.messenger.sockets.client;
// Deitel packages
import com.deitel.messenger.*;
public class DeitelMessenger {
DeitelMesssenger
.java
Lines 10-29
DeitelMessenger starts
SocketMessageManager
// execute application
public static void main( String args[] )
{
MessageManager messageManager;
// create new DeitelMessenger
if ( args.length == 0 )
messageManager = new SocketMessageManager( "localhost" );
else
messageManager = new SocketMessageManager( args[ 0 ] );
// create GUI for SocketMessageManager
ClientGUI clientGUI = new ClientGUI( messageManager );
clientGUI.setSize( 300, 400 );
clientGUI.setResizable( false );
clientGUI.setVisible( true );
}
}
 2002 Prentice Hall, Inc.
All rights reserved.
102
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.
103
Outline
Program Output
 2002 Prentice Hall, Inc.
All rights reserved.