Download 18.6 Client/Server Interaction with Stream Socket - IC

Document related concepts
no text concepts found
Transcript
Chapter 18 - Networking
Outline
18.1
18.2
18.3
18.4
18.5
18.6
18.7
18.8
18.9
18.10
18.11
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
18.10.1 DeitelMessengerServer and Supporting Classes
18.10.2 DeitelMessenger Client and Supporting Classes
NIO Networking Overview
 2003 Prentice Hall, Inc. All rights reserved.
Chapter 18 - Networking
18.12
Used
(Optional) Discovering Design Patterns: Design Patterns
in Packages java.io and java.net
18.12.1 Creational Design Patterns
18.12.2 Structural Design Patterns
18.12.3 Architectural Patterns
18.12.4 Conclusion
 2003 Prentice Hall, Inc. All rights reserved.
18.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)
 2003 Prentice Hall, Inc. All rights reserved.
18.2 Manipulating URLs
• 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
 2003 Prentice Hall, Inc. All rights reserved.
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.htm
l
Declare param tags
Lines 5-12
for the applet
 2003 Prentice Hall, Inc.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Fig. 18.2: SiteSelector.java
// This program uses a button to load a document from a URL.
import java.net.*;
import java.util.*;
import java.awt.*;
import java.applet.AppletContext;
import javax.swing.*;
import javax.swing.event.*;
public class SiteSelector extends JApplet {
private HashMap sites;
// site names and URLs
private Vector siteNames;
// site names
private JList siteChooser; // list of sites to choose from
Outline
SiteSelector.ja
va
Lines 19-20
Create HashMap and
Vector objects
// read HTML parameters and set up GUI
public void init()
{
// create HashMap and Vector
sites = new HashMap();
siteNames = new Vector();
// obtain parameters from HTML document
getSitesFromHTMLParameters();
 2003 Prentice Hall, Inc.
All rights reserved.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// create GUI components and layout interface
Container container = getContentPane();
container.add( new JLabel( "Choose a site to browse" ),
BorderLayout.NORTH );
siteChooser = new JList( siteNames );
siteChooser.addListSelectionListener(
Outline
SiteSelector.ja
va
Line 36
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 );
Line 42
MethodLine 48
valueChanged
goes to the selected
Web site
Create the document
// get reference to applet container
AppletContext browser = getAppletContext();
// tell applet container to change pages
browser.showDocument( newDocument );
}
Show the document
in the browser
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
} // end inner class
Outline
); // end call to addListSelectionListener
container.add( new JScrollPane( siteChooser ),
BorderLayout.CENTER );
SiteSelector.ja
va
} // end method init
Line 68
// obtain parameters from HTML document
private void getSitesFromHTMLParameters()
{
// look for applet parameters in HTML document and add to HashMap
String title, location;
URL url;
int counter = 0;
Line 74
Get Web site title
title = getParameter( "title" + counter ); // get first site title
// loop until no more parameters in HTML document
while ( title != null ) {
// obtain site location
location = getParameter( "location" + counter );
Get Web site location
 2003 Prentice Hall, Inc.
All rights reserved.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// place title/URL in HashMap
try {
url = new URL( location );
sites.put( title, url );
siteNames.add( title );
}
and title in Vector
// convert location to URL
// put title/URL in HashMap
// put title in Vector
// process invalid URL format
catch ( MalformedURLException urlException ) {
urlException.printStackTrace();
}
++counter;
title = getParameter( "title" + counter ); // get next site
} // end while
Outline
SiteSelector.ja
Create
URL of
va
location
Add
URL
Line
78 to
HashMap
Line title
79
Add
to
Vector
Line 80
Get next title from
title
HTMLLine
document
89
} // end method getSitesFromHTMLParameters
} // end class SiteSelector
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
SiteSelector.ja
va
 2003 Prentice Hall, Inc.
All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
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
// Fig. 18.3: ReadServerFile.java
// Use a JEditorPane to display the contents of a file on a Web server.
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
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" );
Outline
ReadServerFile.
java
Line 12
File displayed in
JEditorPane
Container container = getContentPane();
// create enterField and register its listener
enterField = new JTextField( "Enter file URL here" );
enterField.addActionListener(
new ActionListener() {
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Outline
// get document specified by user
public void actionPerformed( ActionEvent event )
{
getThePage( event.getActionCommand() );
}
ReadServerFile.
java
} // end inner class
Line 41
); // 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() );
}
Linea45
Register
HyperlinkListener
Line 48
to handle
HyperlinkEvents
Line 49
Method
hyperlinkUpdate
called when hyperlink
clicked
Determine type of
hyperlink
Get URL of hyperlink
and retrieve page
 2003 Prentice Hall, Inc.
All rights reserved.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
} // end inner class
Outline
); // end call to addHyperlinkListener
container.add( new JScrollPane( contentsArea ),
BorderLayout.CENTER );
setSize( 400, 300 );
setVisible( true );
ReadServerFile.
java
Line 68
} // end constructor ReadServerFile
// load document
private void getThePage( String location )
{
// load document and display location
try {
contentsArea.setPage( location );
enterField.setText( location );
}
catch ( IOException ioException ) {
JOptionPane.showMessageDialog( this,
"Error retrieving specified URL", "Bad URL",
JOptionPane.ERROR_MESSAGE );
}
Method setPage
downloads document
and displays it in
JEditorPane
} // end method getThePage
 2003 Prentice Hall, Inc.
All rights reserved.
78
79
80
81
82
83
84
85
public static void main( String args[] )
{
ReadServerFile application = new ReadServerFile();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
Outline
ReadServerFile.
java
} // end class ReadServerFile
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
ReadServerFile.
java
 2003 Prentice Hall, Inc.
All rights reserved.
18.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 Socket 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
 2003 Prentice Hall, Inc. All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
18.6 Client/Server Interaction with Stream
Socket Connections
• Client/server chat application
– Uses stream sockets as described in last two sections
 2003 Prentice Hall, Inc. All rights reserved.
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
// Fig. 18.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.
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
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;
Outline
Server.java
Lines 15-16
Listen on a
ServerSocket;
the connection is a
Socket
// set up GUI
public Server()
{
super( "Server" );
Container container = getContentPane();
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
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
// create enterField and register listener
enterField = new JTextField();
enterField.setEditable( false );
enterField.addActionListener(
new ActionListener() {
Outline
Server.java
// send message to client
public void actionPerformed( ActionEvent event )
{
sendData( event.getActionCommand() );
enterField.setText( "" );
}
}
);
container.add( enterField, BorderLayout.NORTH );
// create displayArea
displayArea = new JTextArea();
container.add( new JScrollPane( displayArea ),
BorderLayout.CENTER );
setSize( 300, 150 );
setVisible( true );
} // end Server constructor
 2003 Prentice Hall, Inc.
All rights reserved.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Outline
// 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( 12345, 100 );
while ( true ) {
Server.java
Create
Line 60
ServerSocket at
port 12345 with queue
of length 100
try {
waitForConnection(); // Step 2: Wait for a connection.
getStreams();
// Step 3: Get input & output streams.
processConnection(); // Step 4: Process connection.
}
// process EOFException when client closes connection
catch ( EOFException eofException ) {
System.err.println( "Server terminated connection" );
}
finally {
closeConnection();
++counter;
}
// Step 5: Close connection.
 2003 Prentice Hall, Inc.
All rights reserved.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
} // end while
} // end try
// process problems with I/O
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Outline
Server.java
Line 95
Lines 96-97
} // end method runServer
// wait for connection to arrive, then display connection info
private void waitForConnection() throws IOException
{
displayMessage( "Waiting for connection\n" );
connection = server.accept(); // allow server to accept connection
displayMessage( "Connection " + counter + " received from: " +
connection.getInetAddress().getHostName() );
}
Method accept
waits for connection
Output name of
computer that
connected
// get streams to send and receive data
private void getStreams() throws IOException
{
 2003 Prentice Hall, Inc.
All rights reserved.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// set up output stream for objects
output = new ObjectOutputStream( connection.getOutputStream() );
output.flush(); // flush output buffer to send header information
// set up input stream for objects
input = new ObjectInputStream( connection.getInputStream() );
displayMessage( "\nGot I/O streams\n" );
}
Outline
Server.java
Method flush
empties
output
Line
105 buffer
and sends header
information
// process connection with client
private void processConnection() throws IOException
{
// send connection successful message to client
String message = "Connection successful";
sendData( message );
// enable enterField so server user can send messages
setTextFieldEditable( true );
do { // process messages sent from client
 2003 Prentice Hall, Inc.
All rights reserved.
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
// read message and display it
try {
message = ( String ) input.readObject();
displayMessage( "\n" + message );
}
// catch problems reading from client
catch ( ClassNotFoundException classNotFoundException ) {
displayMessage( "\nUnknown object type received" );
}
Outline
Server.java
Read String from
clientLines
and display
it
127-128
Line 141
} while ( !message.equals( "CLIENT>>> TERMINATE" ) );
} // end method processConnection
// close streams and socket
private void closeConnection()
{
displayMessage( "\nTerminating connection\n" );
setTextFieldEditable( false ); // disable enterField
Method
closeConnection
closes streams and
sockets
try {
output.close();
input.close();
connection.close();
}
 2003 Prentice Hall, Inc.
All rights reserved.
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
catch( IOException ioException ) {
ioException.printStackTrace();
}
}
Outline
Server.java
// send message to client
private void sendData( String message )
{
// send object to client
try {
output.writeObject( "SERVER>>> " + message );
output.flush();
displayMessage( "\nSERVER>>> " + message );
}
// process problems sending object
catch ( IOException ioException ) {
displayArea.append( "\nError writing object" );
}
Line 162
Method flush
empties output buffer
and sends header
information
}
// utility method called from other threads to manipulate
// displayArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
 2003 Prentice Hall, Inc.
All rights reserved.
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// display message from event-dispatch thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
public void run() // updates displayArea
{
displayArea.append( messageToDisplay );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
}
Outline
Server.java
// end inner class
); // end call to SwingUtilities.invokeLater
}
// utility method called from other threads to manipulate
// enterField in the event-dispatch thread
private void setTextFieldEditable( final boolean editable )
{
// display message from event-dispatch thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
 2003 Prentice Hall, Inc.
All rights reserved.
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 }
public void run() // sets enterField's editability
{
enterField.setEditable( editable );
}
}
Outline
Server.java
// end inner class
); // end call to SwingUtilities.invokeLater
}
public static void main( String args[] )
{
Server application = new Server();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
application.runServer();
}
// end class Server
 2003 Prentice Hall, Inc.
All rights reserved.
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
Outline
// Fig. 18.5: Client.java
// Client that reads and displays information sent from a Server.
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
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;
Client.java
Line 16
The client is a
Socket
// initialize chatServer and set up GUI
public Client( String host )
{
super( "Client" );
chatServer = host; // set server to which this client connects
Container container = getContentPane();
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// create enterField and register listener
enterField = new JTextField();
enterField.setEditable( false );
enterField.addActionListener(
new ActionListener() {
Outline
Client.java
// send message to server
public void actionPerformed( ActionEvent event )
{
sendData( event.getActionCommand() );
enterField.setText( "" );
}
}
);
container.add( enterField, BorderLayout.NORTH );
// create displayArea
displayArea = new JTextArea();
container.add( new JScrollPane( displayArea ),
BorderLayout.CENTER );
setSize( 300, 150 );
setVisible( true );
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
} // end Client constructor
// connect to server and process messages from server
private void runClient()
{
// connect to server, get streams, process connection
try {
connectToServer(); // Step 1: Create a Socket to make connection
getStreams();
// Step 2: Get the input and output streams
processConnection(); // Step 3: Process connection
}
Outline
Client.java
// server closed connection
catch ( EOFException eofException ) {
System.err.println( "Client terminated connection" );
}
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
finally {
closeConnection(); // Step 4: Close connection
}
 2003 Prentice Hall, Inc.
All rights reserved.
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
} // end method runClient
// connect to server
private void connectToServer() throws IOException
{
displayMessage( "Attempting connection\n" );
// create Socket to make connection to server
client = new Socket( InetAddress.getByName( chatServer ), 12345 );
// display connection information
displayMessage( "Connected to: " +
client.getInetAddress().getHostName() );
}
// get streams to send and receive data
private void getStreams() throws IOException
{
// set up output stream for objects
output = new ObjectOutputStream( client.getOutputStream() );
output.flush(); // flush output buffer to send header information
// set up input stream for objects
input = new ObjectInputStream( client.getInputStream() );
Outline
Client.java
Line 86
Lines 89-90
Create
client
Linesa97
and that
101
will connect with port
12345 on the server
Notify the user that we
have connected
Get the streams to
send and receive data
 2003 Prentice Hall, Inc.
All rights reserved.
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
displayMessage( "\nGot I/O streams\n" );
Outline
}
// process connection with server
private void processConnection() throws IOException
{
// enable enterField so client user can send messages
setTextFieldEditable( true );
Client.java
Line 117
do { // process messages sent from server
// read message and display it
try {
message = ( String ) input.readObject();
displayMessage( "\n" + message );
}
// catch problems reading from server
catch ( ClassNotFoundException classNotFoundException ) {
displayMessage( "\nUnknown object type received" );
}
Read String from
client and display it
} while ( !message.equals( "SERVER>>> TERMINATE" ) );
} // end method processConnection
 2003 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
// close streams and socket
private void closeConnection()
{
displayMessage( "\nClosing connection" );
setTextFieldEditable( false ); // disable enterField
try {
output.close();
input.close();
client.close();
}
catch( IOException ioException ) {
ioException.printStackTrace();
}
Outline
Client.java
Method
Line 130
closeConnection
closes streams and
Line 151
sockets
}
// send message to server
private void sendData( String message )
{
// send object to server
try {
output.writeObject( "CLIENT>>> " + message );
output.flush();
displayMessage( "\nCLIENT>>> " + message );
}
Method flush
empties output buffer
and sends header
information
 2003 Prentice Hall, Inc.
All rights reserved.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// process problems sending object
catch ( IOException ioException ) {
displayArea.append( "\nError writing object" );
}
Outline
Client.java
}
// utility method called from other threads to manipulate
// displayArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
// display message from GUI thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
public void run() // updates displayArea
{
displayArea.append( messageToDisplay );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
}
// end inner class
); // end call to SwingUtilities.invokeLater
}
 2003 Prentice Hall, Inc.
All rights reserved.
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// utility method called from other threads to manipulate
// enterField in the event-dispatch thread
private void setTextFieldEditable( final boolean editable )
{
// display message from GUI thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
Outline
Client.java
public void run() // sets enterField's editability
{
enterField.setEditable( editable );
}
}
// end inner class
); // end call to SwingUtilities.invokeLater
}
public static void main( String args[] )
{
Client application;
 2003 Prentice Hall, Inc.
All rights reserved.
203
if ( args.length == 0 )
204
application = new Client( "127.0.0.1" );
205
else
206
application = new Client( args[ 0 ] );
207
208
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
209
application.runClient();
210
}
211
212 } // end class Client
Outline
Client.java
Create
a client to
Line 204
connect to the localhost
Connect to a host
Line 206
supplied by the user
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
Client.java
 2003 Prentice Hall, Inc.
All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
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
// Fig. 18.6: Server.java
// Server that receives and sends packets from/to a client.
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Server extends JFrame {
private JTextArea displayArea;
private DatagramSocket socket;
Outline
Server.java
Line 11
Line 26
Use a
DatagramSocket
as our server
// 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 );
}
The socket will listen
on port 5000
 2003 Prentice Hall, Inc.
All rights reserved.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Outline
// process problems creating DatagramSocket
catch( SocketException socketException ) {
socketException.printStackTrace();
System.exit( 1 );
}
Server.java
Lines 47-48
} // end Server constructor
Line 50
// wait for packets to arrive, display data and echo packet to client
private void waitForPackets()
{
while ( true ) { // loop forever
// receive packet, display contents, return copy to client
try {
// set up packet
byte data[] = new byte[ 100 ];
DatagramPacket receivePacket =
new DatagramPacket( data, data.length );
socket.receive( receivePacket ); // wait for packet
Create a
DatagramPacket
to store received
information
Method receive
blocks until a packet
is received
 2003 Prentice Hall, Inc.
All rights reserved.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// display information from received packet
displayMessage( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
"\nHost port: " + receivePacket.getPort() +
"\nLength: " + receivePacket.getLength() +
"\nContaining:\n\t" + new String( receivePacket.getData(),
0, receivePacket.getLength() ) );
sendPacketToClient( receivePacket ); // send packet to client
}
// process problems manipulating packet
catch( IOException ioException ) {
displayMessage( ioException.toString() + "\n" );
ioException.printStackTrace();
}
} // end while
} // end method waitForPackets
Outline
Method
Server.java
getAddress
returns
Line
54 name of
computer that sent
Method
getPort
Line packet
55
returns the port the
packet
Linecame
56 through
Method getLength
Line 57
returns the length of
the message sent
Method getData
returns a byte array
containing the sent
data
// echo packet to client
private void sendPacketToClient( DatagramPacket receivePacket )
throws IOException
{
 2003 Prentice Hall, Inc.
All rights reserved.
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
Outline
displayMessage( "\n\nEcho data to client..." );
// create packet to send
DatagramPacket sendPacket = new DatagramPacket(
receivePacket.getData(), receivePacket.getLength(),
receivePacket.getAddress(), receivePacket.getPort() );
Server.java
Create packet to be
sentLines 80-82
socket.send( sendPacket ); // send packet
displayMessage( "Packet sent\n" );
}
// utility method called from other threads to manipulate
// displayArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
// display message from event-dispatch thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
Line 84
Method send sends
the packet over the
network
public void run() // updates displayArea
{
displayArea.append( messageToDisplay );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
 2003 Prentice Hall, Inc.
All rights reserved.
102
103
} // end inner class
104
105
); // end call to SwingUtilities.invokeLater
106
}
107
108
public static void main( String args[] )
109
{
110
Server application = new Server();
111
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
112
application.waitForPackets();
113
}
114
115 } // end class Server
Outline
Server.java
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.7: Client.java
// Client that sends and receives packets to/from a server.
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Client extends JFrame {
private JTextField enterField;
private JTextArea displayArea;
private DatagramSocket socket;
// set up GUI and DatagramSocket
public Client()
{
super( "Client" );
Outline
Client.java
Line 12
Use a
DatagramSocket
as our client
Container container = getContentPane();
enterField = new JTextField( "Type message here" );
enterField.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent event )
{
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// create and send packet
try {
displayArea.append( "\nSending packet containing: " +
event.getActionCommand() + "\n" );
// get message from textfield and convert to byte
String message = event.getActionCommand();
byte data[] = message.getBytes();
Outline
Client.java
Convert the String
array
to a byte
Linearray
33
Lines 36-37
// create sendPacket
DatagramPacket sendPacket = new DatagramPacket( data,
data.length, InetAddress.getLocalHost(), 5000 );
socket.send( sendPacket ); // send packet
displayArea.append( "Packet sent\n" );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
// process problems creating or sending packet
catch ( IOException ioException ) {
displayMessage( ioException.toString() + "\n" );
ioException.printStackTrace();
}
Line 39
Create the
DatagramPacket
to send
Method send sends
the packet over the
network
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
} // end actionPerformed
Outline
} // end inner class
); // end call to addActionListener
container.add( enterField, BorderLayout.NORTH );
Client.java
Line 68
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 a
DatagramSocket
for sending and
receiving packets
// catch problems creating DatagramSocket
catch( SocketException socketException ) {
socketException.printStackTrace();
System.exit( 1 );
}
 2003 Prentice Hall, Inc.
All rights reserved.
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
} // end Client constructor
// wait for packets to arrive from Server, display packet contents
private void waitForPackets()
{
while ( true ) { // loop forever
// receive packet and display contents
try {
// set up packet
byte data[] = new byte[ 100 ];
DatagramPacket receivePacket = new DatagramPacket(
data, data.length );
socket.receive( receivePacket ); // wait for packet
// display packet contents
displayMessage( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
"\nHost port: " + receivePacket.getPort() +
"\nLength: " + receivePacket.getLength() +
"\nContaining:\n\t" + new String( receivePacket.getData(),
0, receivePacket.getLength() ) );
}
Outline
Client.java
Create a
DatagramPacket
Lines
to
store89-90
received
information
Method
receive
Line 92
blocks until a packet
is received
Line
96
Method
Line
97
getAddress
returns
Linename
98 of
computer that sent
Methodpacket
getPort
Line 99
returns the port the
packet came through
Method getLength
returns the length of
the message sent
Method getData
returns a byte array
containing the sent
data
 2003 Prentice Hall, Inc.
All rights reserved.
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
// process problems receiving or displaying packet
catch( IOException exception ) {
displayMessage( exception.toString() + "\n" );
exception.printStackTrace();
}
Outline
Client.java
} // end while
} // end method waitForPackets
// utility method called from other threads to manipulate
// displayArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
// display message from event-dispatch thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
public void run() // updates displayArea
{
displayArea.append( messageToDisplay );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
 2003 Prentice Hall, Inc.
All rights reserved.
127
128
129
130
131
132
133
134
135
136
137
138
139
140 }
}
// end inner class
); // end call to SwingUtilities.invokeLater
}
Outline
Client.java
public static void main( String args[] )
{
Client application = new Client();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
application.waitForPackets();
}
// end class Client
 2003 Prentice Hall, Inc.
All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
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
// Fig. 18.8: TicTacToeServer.java
// This class maintains a game of Tic-Tac-Toe for two client applets.
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import javax.swing.*;
Outline
TicTacToeServer
.java
public class TicTacToeServer extends JFrame {
private char[] board;
private JTextArea outputArea;
private Player[] players;
private ServerSocket server;
private int currentPlayer;
private final int PLAYER_X = 0, PLAYER_O = 1;
private final char X_MARK = 'X', O_MARK = 'O';
// set up tic-tac-toe server and GUI that displays messages
public TicTacToeServer()
{
super( "Tic-Tac-Toe Server" );
board = new char[ 9 ];
players = new Player[ 2 ];
currentPlayer = PLAYER_X;
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// set up ServerSocket
try {
server = new ServerSocket( 12345, 2 );
}
// 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
Create
ServerSocket
to
TicTacToeServer
listen on .java
port 12345
Line 29
Line 49
Method execute
waits for two
connections to start
game
} // end TicTacToeServer constructor
// wait for two connections so game can be played
public void execute()
{
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 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();
}
// process problems receiving connection from client
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
Outline
TicTacToeServer
Block
while waiting
.java
for each player
Line 56
Call start method
Line
57
to begin
executing
thread
}
// Player X is suspended until Player O connects.
// Resume player X now.
synchronized ( players[ PLAYER_X ] ) {
players[ PLAYER_X ].setSuspended( false );
players[ PLAYER_X ].notify();
}
}
// end method execute
 2003 Prentice Hall, Inc.
All rights reserved.
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
// utility method called from other threads to manipulate
// outputArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
// display message from event-dispatch thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
Outline
TicTacToeServer
.java
public void run() // updates outputArea
{
outputArea.append( messageToDisplay );
outputArea.setCaretPosition(
outputArea.getText().length() );
}
}
// end inner class
); // end call to SwingUtilities.invokeLater
}
// Determine if a move is valid. This method is synchronized because
// only one move can be made at a time.
public synchronized boolean validateAndMove( int location, int player )
{
boolean moveDone = false;
 2003 Prentice Hall, Inc.
All rights reserved.
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
// while not current player, must wait for turn
while ( player != currentPlayer ) {
// wait for turn
try {
wait();
}
Outline
TicTacToeServer
.java
// catch wait interruptions
catch( InterruptedException interruptedException ) {
interruptedException.printStackTrace();
}
}
// if location not occupied, make move
if ( !isOccupied( location ) ) {
// set move in board array
board[ location ] = currentPlayer == PLAYER_X ? X_MARK : O_MARK;
// change current player
currentPlayer = ( currentPlayer + 1 ) % 2;
// let new current player know that move occurred
players[ currentPlayer ].otherPlayerMoved( location );
 2003 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
notify(); // tell waiting player to continue
// tell player that made move that the move was valid
return true;
}
Outline
TicTacToeServer
.java
// tell player that made move that the move was not valid
else
return false;
} // end method validateAndMove
// determine whether location is occupied
public boolean isOccupied( int location )
{
if ( board[ location ] == X_MARK || board [ location ] == O_MARK )
return true;
else
return false;
}
// place code in this method to determine whether game over
public boolean isGameOver()
{
return false; // this is left as an exercise
}
 2003 Prentice Hall, Inc.
All rights reserved.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
public static void main( String args[] )
{
TicTacToeServer application = new TicTacToeServer();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
application.execute();
}
Outline
TicTacToeServer
.java
// 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;
// set up Player thread
public Player( Socket socket, int number )
{
playerNumber = number;
// specify player's mark
mark = ( playerNumber == PLAYER_X ? X_MARK : O_MARK );
 2003 Prentice Hall, Inc.
All rights reserved.
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
Outline
connection = socket;
// obtain streams from Socket
try {
input = new DataInputStream( connection.getInputStream() );
output = new DataOutputStream( connection.getOutputStream() );
}
// process problems getting streams
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
TicTacToeServer
.java
Lines
Get
the183-184
streams to
send and receive data
Lines 200-201
} // end Player constructor
// send message that other player moved
public void otherPlayerMoved( int location )
{
// send message indicating move
try {
output.writeUTF( "Opponent moved" );
output.writeInt( location );
}
Send output notifying the
other player of the move
 2003 Prentice Hall, Inc.
All rights reserved.
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
// process problems sending message
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
// control thread's execution
public void run()
{
// send client message indicating its mark (X or O),
// process messages from client
try {
displayMessage( "Player " + ( playerNumber ==
PLAYER_X ? X_MARK : O_MARK ) + " connected\n" );
output.writeChar( mark ); // send player's mark
// send message indicating connection
output.writeUTF( "Player " + ( playerNumber == PLAYER_X ?
"X connected\n" : "O connected, please wait\n" ) );
Outline
TicTacToeServer
.java
Line 219
Line 227
Send player’s mark
Wait for other player
// if player X, wait for another player to arrive
if ( mark == X_MARK ) {
output.writeUTF( "Waiting for another player" );
 2003 Prentice Hall, Inc.
All rights reserved.
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// wait for player O
try {
synchronized( this ) {
while ( suspended )
wait();
}
}
Outline
TicTacToeServer
.java
Line 244
// process interruptions while waiting
catch ( InterruptedException exception ) {
exception.printStackTrace();
}
Line 251
Begin the game
// 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 ( ! isGameOver() ) {
// get move location from client
int location = input.readInt();
Read a move
 2003 Prentice Hall, Inc.
All rights reserved.
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
// check for valid move
if ( validateAndMove( location, playerNumber ) ) {
displayMessage( "\nlocation: " + location );
output.writeUTF( "Valid move." );
}
else
output.writeUTF( "Invalid move, try again" );
}
Outline
TicTacToeServer
Send message
to
.java
client
Line 256
connection.close(); // close connection to client
} // end try
// process problems communicating with client
catch( IOException ioException ) {
ioException.printStackTrace();
System.exit( 1 );
}
} // end method run
// set whether or not thread is suspended
public void setSuspended( boolean status )
{
suspended = status;
}
 2003 Prentice Hall, Inc.
All rights reserved.
279
280
} // end class Player
281
282 } // end class TicTacToeServer
Outline
TicTacToeServer
.java
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.9: TicTacToeClient.java
// Client that let a user play Tic-Tac-Toe with another across a network.
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import javax.swing.*;
Outline
TicTacToeClient
.java
public class TicTacToeClient extends JApplet implements Runnable {
private JTextField idField;
private JTextArea displayArea;
private JPanel boardPanel, panel2;
private Square board[][], currentSquare;
private Socket connection;
private DataInputStream input;
private DataOutputStream output;
private char myMark;
private boolean myTurn;
private final char X_MARK = 'X', O_MARK = 'O';
// Set up user-interface and board
public void init()
{
Container container = getContentPane();
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// set up JTextArea to display messages to user
displayArea = new JTextArea( 4, 30 );
displayArea.setEditable( false );
container.add( new JScrollPane( displayArea ), BorderLayout.SOUTH );
// set up panel for squares in board
boardPanel = new JPanel();
boardPanel.setLayout( new GridLayout( 3, 3, 0, 0 ) );
Outline
TicTacToeClient
.java
// 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 ] );
}
}
 2003 Prentice Hall, Inc.
All rights reserved.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// textfield to display player's mark
idField = new JTextField();
idField.setEditable( false );
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 );
} // end method init
// Make connection to server and get associated streams.
// Start separate thread to allow this applet to
// continually update its output in textarea display.
public void start()
{
// connect to server, get streams and start outputThread
try {
Outline
TicTacToeClient
.java
Line 73
Lines 76-77
Connect to the server
// make connection
connection = new Socket( getCodeBase().getHost(), 12345 );
// get streams
input = new DataInputStream( connection.getInputStream() );
output = new DataOutputStream( connection.getOutputStream() );
Get the streams to
send and receive data
 2003 Prentice Hall, Inc.
All rights reserved.
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
Outline
}
// catch problems setting up connection and streams
catch ( IOException ioException ) {
ioException.printStackTrace();
}
// create and start output thread
Thread outputThread = new Thread( this );
outputThread.start();
TicTacToeClient
.java
Line 96
} // end method start
// control thread that allows continuous update of displayArea
public void run()
{
// get player's mark (X or O)
try {
myMark = input.readChar();
// display player ID in event-dispatch thread
SwingUtilities.invokeLater(
new Runnable() {
public void run()
{
Read mark character
from server
 2003 Prentice Hall, Inc.
All rights reserved.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
idField.setText( "You are player \"" + myMark + "\"" );
}
Outline
}
);
myTurn = ( myMark == X_MARK ? true : false );
// receive messages sent to client and output them
while ( true ) {
processMessage( input.readUTF() );
}
} // end try
TicTacToeClient
.java
Loop continually
Line 111
Line 112
Read and process
messages from server
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
}
// end method run
// process messages received by client
private void processMessage( String message )
{
 2003 Prentice Hall, Inc.
All rights reserved.
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
// valid move occurred
if ( message.equals( "Valid move." ) ) {
displayMessage( "Valid move, please wait.\n" );
setMark( currentSquare, myMark );
}
// invalid move occurred
else if ( message.equals( "Invalid move, try again" ) ) {
displayMessage( message + "\n" );
myTurn = true;
}
// opponent moved
else if ( message.equals( "Opponent moved" ) ) {
// get
try {
int
int
int
move location and update board
Outline
TicTacToeClient
If valid move,
write
.java
message and set mark
in square
Line 128
Line 134
If invalid move,
displayLine
message
140
If opponent moves,
set mark in square
location = input.readInt();
row = location / 3;
column = location % 3;
setMark( board[ row ][ column ],
( myMark == X_MARK ? O_MARK : X_MARK ) );
displayMessage( "Opponent moved. Your turn.\n" );
myTurn = true;
 2003 Prentice Hall, Inc.
All rights reserved.
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
} // end try
// process problems communicating with server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
Outline
TicTacToeClient
.java
} // end else if
// simply display message
else
displayMessage( message + "\n" );
} // end method processMessage
// utility method called from other threads to manipulate
// outputArea in the event-dispatch thread
private void displayMessage( final String messageToDisplay )
{
// display message from event-dispatch thread of execution
SwingUtilities.invokeLater(
new Runnable() { // inner class to ensure GUI updates properly
 2003 Prentice Hall, Inc.
All rights reserved.
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
public void run() // updates displayArea
{
displayArea.append( messageToDisplay );
displayArea.setCaretPosition(
displayArea.getText().length() );
}
}
Outline
TicTacToeClient
.java
// end inner class
); // end call to SwingUtilities.invokeLater
}
// utility method to set mark on board in event-dispatch thread
private void setMark( final Square squareToMark, final char mark )
{
SwingUtilities.invokeLater(
new Runnable() {
public void run()
{
squareToMark.setMark( mark );
}
}
);
}
 2003 Prentice Hall, Inc.
All rights reserved.
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// 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();
}
Outline
TicTacToeClient
.java
Line 208
Send the move to the
server
}
}
// set current Square
public void setCurrentSquare( Square square )
{
currentSquare = square;
}
 2003 Prentice Hall, Inc.
All rights reserved.
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// private inner class for the squares on the board
private class Square extends JPanel {
private char mark;
private int location;
public Square( char squareMark, int squareLocation )
{
mark = squareMark;
location = squareLocation;
Outline
TicTacToeClient
.java
addMouseListener(
new MouseAdapter() {
public void mouseReleased( MouseEvent e )
{
setCurrentSquare( Square.this );
sendClickedSquare( getSquareLocation() );
}
}
);
} // end Square constructor
// return preferred size of Square
public Dimension getPreferredSize()
{
 2003 Prentice Hall, Inc.
All rights reserved.
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
return new Dimension( 30, 30 );
}
// 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 )
{
 2003 Prentice Hall, Inc.
All rights reserved.
275
super.paintComponent( g );
276
277
g.drawRect( 0, 0, 29, 29 );
278
g.drawString( String.valueOf( mark ), 11, 20 );
279
}
280
281
} // end inner-class Square
282
283 } // end class TicTacToeClient
Outline
TicTacToeClient
.java
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
TicTacToeClient
.java
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
TicTacToeClient
.java
 2003 Prentice Hall, Inc.
All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Fig. 18.11: DeitelMessengerServer.java
// DeitelMessengerServer is a multi-threaded, socket- and
// packet-based chat server.
package com.deitel.messenger.sockets.server;
import java.util.*;
import java.net.*;
import java.io.*;
Outline
DeitelMessenger
Server.java
Line 13
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
public class DeitelMessengerServer implements MessageListener {
// start chat server
public void startServer()
{
// create server and manage new clients
try {
Implement the
MessageListener
interface
// create ServerSocket for incoming connections
ServerSocket serverSocket = new ServerSocket(
SocketMessengerConstants.SERVER_PORT, 100 );
 2003 Prentice Hall, Inc.
All rights reserved.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
System.out.println( "Server listening on port " +
SocketMessengerConstants.SERVER_PORT + " ..." );
// listen for clients constantly
while ( true ) {
// accept new client connection
Socket clientSocket = serverSocket.accept();
Outline
DeitelMessenger
Server.java
// create new ReceivingThread for receiving
// messages from client
new ReceivingThread( this, clientSocket ).start();
32
InvokeLine
method
accept to wait for
Linea36
and accept
new
client connection
// print connection information
System.out.println( "Connection received from: " +
clientSocket.getInetAddress() );
Create and start a new
ReceivingThread
} // end while
} // end try
// handle exception creating server and connecting clients
catch ( IOException ioException ) {
ioException.printStackTrace();
}
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Outline
} // end method startServer
// when new message is received, broadcast message to clients
public void messageReceived( String from, String message )
{
// create String containing entire message
String completeMessage = from +
SocketMessengerConstants.MESSAGE_SEPARATOR + message;
Method
DeitelMessenger
messageReceived
Server.java
broadcasts new
messagesLine
to clients
54
// create and start MulticastSendingThread to broadcast
// new messages to all clients
new MulticastSendingThread( completeMessage.getBytes() ).start();
Line 62
}
public static void main ( String args[] )
{
new DeitelMessengerServer().startServer();
}
Create and start new
MulticastSendingThread
to send messages to all clients
} // end class DeitelMessengerServer
Server listening on port 5000 ...
Connection received from: SEANSANTRY/XXX.XXX.XXX.XXX
Connection received from: PJD/XXX.XXX.XXX.XXX
 2003 Prentice Hall, Inc.
All rights reserved.
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. 18.12: SocketMessengerConstants.java
// SocketMessengerConstants declares 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 = "239.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
SocketMessenger
Constants.java
Line 9
Address to send
multicast datagrams
Line 12
Port listening for
15
multicast Line
datagrams
Port for
sending
Line
18
multicast datagrams
Line 21
Port for socket
connections
Lineto
24server
String that
27
indicatesLine
disconnect
String that
separates user name
and message
Maximum message
sizein2003
bytes
Prentice Hall, Inc.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
// Fig. 18.13: 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
MessageListener
.java
Method
Line 9
messageReceived
allows an
implementing class to
receive messages
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.14: 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;
import java.io.*;
import java.net.*;
import java.util.StringTokenizer;
Outline
ReceivingThread
.java
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
public class ReceivingThread extends Thread {
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;
 2003 Prentice Hall, Inc.
All rights reserved.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// set timeout for reading from clientSocket and create
// BufferedReader for reading incoming messages
try {
clientSocket.setSoTimeout( 5000 );
input = new BufferedReader( new InputStreamReader(
clientSocket.getInputStream() ) );
Outline
ReceivingThread
Attempt to read.java
for
five seconds
Line 31
}
// handle exception creating BufferedReader
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end ReceivingThread constructor
// listen for new messages and deliver them to MessageListener
public void run()
{
String message;
// listen for messages until stopped
while ( keepListening ) {
 2003 Prentice Hall, Inc.
All rights reserved.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// read message from BufferedReader
try {
message = input.readLine();
}
Outline
Read line of data from ReceivingThread
client
.java
// handle exception if read times out
catch ( InterruptedIOException interruptedIOException ) {
// continue to next iteration to keep listening
continue;
}
Line 54
An InterruptedException
is thrown if the Line
read times
58 out
Lines 74-75
// handle exception reading message
catch ( IOException ioException ) {
ioException.printStackTrace();
break;
}
// ensure non-null message
if ( message != null ) {
Separate message into two
tokens delimited by
body Message_SEPARATOR
// tokenize message to retrieve user name and message
StringTokenizer tokenizer = new StringTokenizer(
message, SocketMessengerConstants.MESSAGE_SEPARATOR );
 2003 Prentice Hall, Inc.
All rights reserved.
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
// 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
Outline
ReceivingThread
.java
Lines 89-92
else
// if disconnect message received, stop listening
if ( message.equalsIgnoreCase(
SocketMessengerConstants.MESSAGE_SEPARATOR +
SocketMessengerConstants.DISCONNECT_STRING ) )
stopListening();
} // end if
} // end while
Determine whether
message indicates that user
wishes to leave chat room
// close BufferedReader (also closes Socket)
try {
input.close();
}
 2003 Prentice Hall, Inc.
All rights reserved.
102
103
// handle exception closing BufferedReader
104
catch ( IOException ioException ) {
105
ioException.printStackTrace();
106
}
107
108
} // end method run
109
110
// stop listening for incoming messages
111
public void stopListening()
112
{
113
keepListening = false;
114
}
115
116 } // end class ReceivingThread
Outline
ReceivingThread
.java
 2003 Prentice Hall, Inc.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Fig. 18.15: MulticastSendingThread.java
// MulticastSendingThread is a Thread that broadcasts a chat
// message using a multicast datagram.
package com.deitel.messenger.sockets.server;
import java.io.*;
import java.net.*;
Outline
MulticastSendin
gThread.java
import com.deitel.messenger.sockets.*;
public class MulticastSendingThread extends Thread {
// message data
private byte[] messageBytes;
// MulticastSendingThread constructor
public MulticastSendingThread( byte[] bytes )
{
// invoke superclass constructor to name Thread
super( "MulticastSendingThread" );
messageBytes = bytes;
}
 2003 Prentice Hall, Inc.
All rights reserved.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// deliver message to MULTICAST_ADDRESS over DatagramSocket
public void run()
{
// deliver message
try {
// create DatagramSocket for sending message
DatagramSocket socket = new DatagramSocket(
SocketMessengerConstants.MULTICAST_SENDING_PORT );
// use InetAddress reserved for multicast group
InetAddress group = InetAddress.getByName(
SocketMessengerConstants.MULTICAST_ADDRESS );
// create DatagramPacket containing message
DatagramPacket packet = new DatagramPacket( messageBytes,
messageBytes.length, group,
SocketMessengerConstants.MULTICAST_LISTENING_PORT );
// send packet to multicast group and close socket
socket.send( packet );
socket.close();
Outline
MulticastSendin
gThread.java
Create DatagramSocket for
Lines 32-33
delivering DatagramPackets
via multicast
Lines 36-37
Linesaddress
40-42 and 45
Specify multicast
Create DatagramPacket
and send it to clients
}
 2003 Prentice Hall, Inc.
All rights reserved.
49
50
51
52
53
54
55
56
// handle exception delivering message
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end method run
Outline
MulticastSendin
gThread.java
} // end class MulticastSendingThread
 2003 Prentice Hall, Inc.
All rights reserved.
18.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
 2003 Prentice Hall, Inc. All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Fig. 18.16: MessageManager.java
// MessageManager is an interface for objects capable of managing
// communications with a message server.
package com.deitel.messenger;
public interface MessageManager {
// 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 );
Outline
MessageManager.
Connects MessageManager
to
java
DeitelMessengerServer and
routes incoming messages to
Line 10
appropriate MessageListener
Line 14
Disconnects MessageManager
from DeitelMessengerServer
Line 17
and stops delivering messages to
MessageListener
// send message to message server
public void sendMessage( String from, String message );
}
Sends new message to
DeitelMessengerServer
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.17: SocketMessageManager.java
// SocketMessageManager communicates with a DeitelMessengerServer using
// Sockets and MulticastSockets.
package com.deitel.messenger.sockets.client;
import java.util.*;
import java.net.*;
import java.io.*;
Outline
SocketMessageMa
nager.java
Line 16
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
Line 22
public class SocketMessageManager implements MessageManager {
// 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;
Thread listens for
incoming messages
// flag indicating connection status
private boolean connected = false;
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Outline
// SocketMessageManager constructor
public SocketMessageManager( String address )
{
serverAddress = address;
}
SocketMessageMa
nager.java
// connect to server and send messages to given MessageListener
public void connect( MessageListener listener )
{
// if already connected, return immediately
if ( connected )
return;
// open Socket connection to DeitelMessengerServer
try {
clientSocket = new Socket(
InetAddress.getByName( serverAddress ),
SocketMessengerConstants.SERVER_PORT );
Lines 42-44
Line 48
Create Socket to
communicate with
DeitelMessengerServer
// create Thread for receiving incoming messages
receivingThread = new PacketReceivingThread( listener );
receivingThread.start();
// update connected flag
connected = true;
Start Thread that listens
for incoming messages
 2003 Prentice Hall, Inc.
All rights reserved.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Outline
}
// handle exception connecting to server
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // end method connect
SocketMessageMa
nager.java
Terminates SocketMessageManager
connection to DeitelMessengerServer
Line 62
// disconnect from server and unregister given MessageListener
public void disconnect( MessageListener listener )
{
// if not connected, return immediately
if ( !connected )
return;
// stop listening thread and disconnect from server
try {
// notify server that client is disconnecting
Thread disconnectThread = new SendingThread( clientSocket, "",
SocketMessengerConstants.DISCONNECT_STRING );
disconnectThread.start();
 2003 Prentice Hall, Inc.
All rights reserved.
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
// wait 10 seconds for disconnect message to be sent
disconnectThread.join( 10000 );
// stop receivingThread and remove given MessageListener
receivingThread.stopListening();
Outline
SocketMessageMa
nager.java
// close outgoing Socket
clientSocket.close();
} // 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
 2003 Prentice Hall, Inc.
All rights reserved.
101
102
// send message to server
103
public void sendMessage( String from, String message )
104
{
105
// if not connected, return immediately
106
if ( !connected )
107
return;
108
109
// create and start new SendingThread to deliver message
110
new SendingThread( clientSocket, from, message).start();
111
}
112
113 } // end method SocketMessageManager
Outline
SocketMessageMa
nager.java
Line 110
Send message to
DeitelMessengerServer
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.18: SendingThread.java
// SendingThread sends a message to the chat server in a separate Thread.
package com.deitel.messenger.sockets.client;
import java.io.*;
import java.net.*;
Outline
SendingThread.j
ava
import com.deitel.messenger.sockets.*;
public class SendingThread extends Thread {
// 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 +
SocketMessengerConstants.MESSAGE_SEPARATOR + message;
 2003 Prentice Hall, Inc.
All rights reserved.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Outline
}
// 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
}
// handle exception sending message
catch ( IOException ioException ) {
ioException.printStackTrace();
}
SendingThread.j
ava
Lines 34-37
method println of class
PrintWriter to send message
to DeitelMessengerServer
}
} // end class SendingThread
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.19: PacketReceivingThread.java
// PacketReceivingThread listens for DatagramPackets containing
// messages from a DeitelMessengerServer.
package com.deitel.messenger.sockets.client;
import java.io.*;
import java.net.*;
import java.util.*;
Outline
PacketReceiving
Thread.java
import com.deitel.messenger.*;
import com.deitel.messenger.sockets.*;
public class PacketReceivingThread extends Thread {
// MessageListener to whom messages should be delivered
private MessageListener messageListener;
// MulticastSocket for receiving broadcast messages
private MulticastSocket multicastSocket;
// InetAddress of group for messages
private InetAddress multicastGroup;
// flag for terminating PacketReceivingThread
private boolean keepListening = true;
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Outline
// PacketReceivingThread constructor
public PacketReceivingThread( MessageListener listener )
{
// invoke superclass constructor to name Thread
super( "PacketReceivingThread" );
// set MessageListener
messageListener = listener;
PacketReceiving
Thread.java
Lines 38-39
MulticastSocket listens for
incoming chat messages Lines
on port41-42
and
port
MULTICAST_LISTENING_PORT
Line 45
// connect MulticastSocket to multicast address
try {
multicastSocket = new MulticastSocket(
SocketMessengerConstants.MULTICAST_LISTENING_PORT );
multicastGroup = InetAddress.getByName(
SocketMessengerConstants.MULTICAST_ADDRESS );
// join multicast group to receive messages
multicastSocket.joinGroup( multicastGroup );
InetAddress object to which
DeitelMessengerServer
multicasts chat messages
// set 5 second timeout when waiting for new packetsRegister MulticastSocket
multicastSocket.setSoTimeout( 5000 );
to receive messages sent to
}
MULTICAST_ADDRESS
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// handle exception connecting to multicast address
catch ( IOException ioException ) {
ioException.printStackTrace();
}
} // 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[ SocketMessengerConstants.MESSAGE_SIZE ];
// create DatagramPacket for incoming message
DatagramPacket packet = new DatagramPacket( buffer,
SocketMessengerConstants.MESSAGE_SIZE );
// receive new DatagramPacket (blocking call)
try {
multicastSocket.receive( packet );
}
Outline
PacketReceiving
Thread.java
Lines 65-66
Lines 69-70
Line 74
Create byte array for
storing DatagramPacket
Create DatagramPacket
for storing message
Read incoming packet
from multicast address
 2003 Prentice Hall, Inc.
All rights reserved.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// handle exception when receive times out
catch ( InterruptedIOException interruptedIOException ) {
// continue to next iteration to keep listening
continue;
Outline
PacketReceiving
Thread.java
}
Lines 97-98
// handle exception reading packet from multicast group
catch ( IOException ioException ) {
ioException.printStackTrace();
break;
}
// put message data in a String
String message = new String( packet.getData() );
// trim extra white space from end of message
message = message.trim();
// tokenize message to retrieve user name and message body
StringTokenizer tokenizer = new StringTokenizer(
message, SocketMessengerConstants.MESSAGE_SEPARATOR );
Separate message into two
tokens delimited by
Message_SEPARATOR
 2003 Prentice Hall, Inc.
All rights reserved.
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// 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 while
Outline
PacketReceiving
Thread.java
Lines 105-107
After parsing message, deliver message to
Line 113
PacketReceivingThread’s
MessageListener
MulticastSocket
// leave multicast group and close
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
 2003 Prentice Hall, Inc.
All rights reserved.
124
// stop listening for new messages
125
public void stopListening()
126
{
127
keepListening = false;
128
}
129
130 } // end class PacketReceivingThread
Outline
PacketReceiving
Thread.java
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.20: ClientGUI.java
// ClientGUI provides a user interface for sending and receiving
// messages to and from the DeitelMessengerServer.
package com.deitel.messenger;
import
import
import
import
import
import
Outline
ClientGUI.java
java.io.*;
java.net.*;
java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.border.*;
public class ClientGUI extends JFrame {
// JMenu for connecting/disconnecting server
private JMenu serverMenu;
// JTextAreas for displaying and inputting messages
private JTextArea messageArea;
private JTextArea inputArea;
// JButtons and JMenuItems for connecting and disconnecting
private JButton connectButton;
private JMenuItem connectMenuItem;
private JButton disconnectButton;
private JMenuItem disconnectMenuItem;
 2003 Prentice Hall, Inc.
All rights reserved.
27
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
// JButton for sending messages
private JButton sendButton;
// JLabel for displaying connection status
private JLabel statusBar;
// 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
Line 38
Line 41
MessageManager handles
communication with chat server
MessageListener
receives incoming messages
from MessageManager
// set the MessageManager
messageManager = manager;
// create MyMessageListener for receiving messages
messageListener = new MyMessageListener();
 2003 Prentice Hall, Inc.
All rights reserved.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// create Server JMenu
serverMenu = new JMenu ( "Server" );
serverMenu.setMnemonic( 'S' );
JMenuBar menuBar = new JMenuBar();
menuBar.add( serverMenu );
setJMenuBar( menuBar );
Outline
ClientGUI.java
// create ImageIcon for connect buttons
Icon connectIcon = new ImageIcon(
getClass().getResource( "images/Connect.gif" ) );
// 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 );
// create ImageIcon for disconnect buttons
Icon disconnectIcon = new ImageIcon(
getClass().getResource( "images/Disconnect.gif" ) );
 2003 Prentice Hall, Inc.
All rights reserved.
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
// create disconnectButton and disconnectMenuItem
disconnectButton = new JButton( "Disconnect", disconnectIcon );
disconnectMenuItem = new JMenuItem( "Disconnect", disconnectIcon );
disconnectMenuItem.setMnemonic( 'D' );
Outline
ClientGUI.java
// 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 );
// 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();
 2003 Prentice Hall, Inc.
All rights reserved.
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
// disable editing and wrap words at end of line
messageArea.setEditable( false );
messageArea.setWrapStyleWord( true );
messageArea.setLineWrap( true );
Outline
ClientGUI.java
// put messageArea in JScrollPane to enable scrolling
JPanel messagePanel = new JPanel();
messagePanel.setLayout( new BorderLayout( 10, 10 ) );
messagePanel.add( new JScrollPane( messageArea ),
BorderLayout.CENTER );
// 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 );
 2003 Prentice Hall, Inc.
All rights reserved.
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
Outline
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( "" );
}
ClientGUI.java
Lines 136-137
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 ) );
 2003 Prentice Hall, Inc.
All rights reserved.
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// lay out components in JFrame
Container container = getContentPane();
container.add( buttonPanel, BorderLayout.NORTH );
container.add( messagePanel, BorderLayout.CENTER );
container.add( statusBar, BorderLayout.SOUTH );
Outline
ClientGUI.java
Line 170
// add WindowListener to disconnect when user quits
addWindowListener (
new WindowAdapter () {
// disconnect from server and exit application
public void windowClosing ( WindowEvent event )
{
messageManager.disconnect( messageListener );
System.exit( 0 );
}
}
);
Disconnect from chat server when
user exits client application
} // end ClientGUI constructor
// ConnectListener listens for user requests to connect to server
private class ConnectListener implements ActionListener {
 2003 Prentice Hall, Inc.
All rights reserved.
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
// connect to server and enable/disable GUI components
public void actionPerformed( ActionEvent event )
{
// connect to server and route messages to messageListener
When
messageManager.connect( messageListener );
Outline
ClientGUI.java
user accesses Connect
menu, connect to chat
Lineserver
185
// prompt for userName
userName = JOptionPane.showInputDialog(
ClientGUI.this, "Enter user name:" );
// clear messageArea
messageArea.setText( "" );
// 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 );
}
 2003 Prentice Hall, Inc.
All rights reserved.
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
} // end ConnectListener inner class
// DisconnectListener listens for user requests to disconnect
// from DeitelMessengerServer
private class DisconnectListener implements ActionListener {
Outline
ClientGUI.java
// 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 components
sendButton.setEnabled( false );
disconnectButton.setEnabled( false );
disconnectMenuItem.setEnabled( false );
inputArea.setEditable( false );
connectButton.setEnabled( true );
connectMenuItem.setEnabled( true );
statusBar.setText( "Not Connected" );
}
} // end DisconnectListener inner class
 2003 Prentice Hall, Inc.
All rights reserved.
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// MyMessageListener listens for new messages from MessageManager and
// displays messages in messageArea using 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 ) );
}
Outline
ClientGUI.java
Lines 239-240
Display message when
MessageListener detects that
message was received
}
// MessageDisplayer displays a new message 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 constructor
public MessageDisplayer( String from, String body )
 2003 Prentice Hall, Inc.
All rights reserved.
253
{
254
fromUser = from;
255
messageBody = body;
256
}
257
258
// display new message in messageArea
259
public void run()
260
{
261
// append new message
262
messageArea.append( "\n" + fromUser + "> " + messageBody );
263
264
// move caret to end of messageArea to ensure new
265
// message is visible on screen
266
messageArea.setCaretPosition( messageArea.getText().length() );
267
}
268
269
} // end MessageDisplayer inner class
270
271 } // end class ClientGUI
Outline
ClientGUI.java
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.21 DeitelMessenger.java
// DeitelMessenger is a chat application that uses a ClientGUI
// and SocketMessageManager to communicate with DeitelMessengerServer.
package com.deitel.messenger.sockets.client;
import com.deitel.messenger.*;
public class DeitelMessenger {
Outline
DeitelMessenger
.java
DeitelMessenger creates
Lines 8 and 16-18
SocketMessageManager
public static void main( String args[] )
{
MessageManager messageManager;
Line 16
Line 18
// 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 );
Create a client to
connect to the localhost
Connect to a host
supplied by the user
}
} // end class DeitelMessenger
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
DeitelMessenger
.java
 2003 Prentice Hall, Inc.
All rights reserved.
Outline
DeitelMessenger
.java
 2003 Prentice Hall, Inc.
All rights reserved.
18.11 NIO Networking Overview
• Non-blocking I/O
• Readiness selection
– Selectors
• SelectableChannel
• Selector
 2003 Prentice Hall, Inc. All rights reserved.
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
// Fig. 18.22: DeitelMessengerNonBlockingServer.java
// Set up a nonblocking chatServer that will receive a connection from a
// client and echo client's message to all connected clients.
package com.deitel.messenger.sockets.server;
import
import
import
import
import
import
import
import
import
java.io.*;
java.nio.*;
java.nio.channels.*;
java.nio.channels.spi.*;
java.nio.charset.*;
java.net.*;
java.util.*;
java.awt.event.*;
javax.swing.*;
Outline
DeitelMessenger
NonBlockingServ
er.java
public class DeitelMessengerNonBlockingServer extends JFrame {
private ServerSocketChannel serverSocketChannel;
private Selector selector;
private Vector sockets = new Vector();
private int counter = 0;
private JTextArea displayArea;
private Charset charSet;
private ByteBuffer writeBuffer;
private ByteBuffer readBuffer = ByteBuffer.allocate( 512 );
 2003 Prentice Hall, Inc.
All rights reserved.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public DeitelMessengerNonBlockingServer()
{
super( "DeitelMessenger Server" );
displayArea = new JTextArea();
getContentPane().add( new JScrollPane( displayArea ) );
setSize( 200, 300 );
setVisible( true );
Outline
DeitelMessenger
NonBlockingServ
er.java
Lines 45-46
// close server socket channel and selector when closing window
addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent windowEvent )
{
// close server socket channel and selector
try {
serverSocketChannel.close();
selector.close();
}
catch( IOException ioException ) {
ioException.printStackTrace();
}
Close the server and
the selector
 2003 Prentice Hall, Inc.
All rights reserved.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
finally {
System.exit( 0 );
}
}
} // end inner class WindowAdapter
Outline
DeitelMessenger
NonBlockingServ
er.java
); // end addWindowListener
Line 69
} // end constructor
// set up and run server
public void runServer()
{
// set up server to receive connections; process connections
try {
// specify the char set used to encode/decode messages
charSet = Charset.forName( "UTF-8" );
// create a ServerSocketChannel
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(
new InetSocketAddress( 12345 ) );
serverSocketChannel.configureBlocking( false );
Line 75
Create a Charset for
UTF-8 encoding
Set up the server to be
non-blocking
 2003 Prentice Hall, Inc.
All rights reserved.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// wait for a connection
getConnection();
} // end try
// process problems with I/O
catch ( Exception ioException ) {
ioException.printStackTrace();
}
} // end method runServer
// wait for connection to arrive, then display connection info
private void getConnection() throws Exception
{
// Selector for incoming requests
selector = SelectorProvider.provider().openSelector();
serverSocketChannel.register(
selector, SelectionKey.OP_ACCEPT, null );
Outline
DeitelMessenger
NonBlockingServ
er.java
Line 93
Lines 94-95
Create the selector
Register the server with
the selector
// process incoming requests
while ( selector.select() > 0 ) {
 2003 Prentice Hall, Inc.
All rights reserved.
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
// get channels ready for i/o
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
// for each ready channel, process request
while ( iterator.hasNext() ) {
SelectionKey key = ( SelectionKey )iterator.next();
iterator.remove();
Outline
DeitelMessenger
NonBlockingServ
er.java
Line 114
if ( key.isAcceptable() ) {
// ready for connection
// create connection
ServerSocketChannel nextReady =
( ServerSocketChannel ) key.channel();
SocketChannel socketChannel = nextReady.accept();
if ( socketChannel != null ) {
socketChannel.configureBlocking( false );
sockets.add( socketChannel.socket() );
counter++;
Accept a new connection
SwingUtilities.invokeLater(
new Runnable() {
 2003 Prentice Hall, Inc.
All rights reserved.
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
public void run()
{
displayArea.append(
"\nConnection with Client " + counter );
}
}
);
// register read operation to socketChannel
SelectionKey readKey = socketChannel.register(
selector, SelectionKey.OP_READ, null );
} // end if socketChannel != null
Outline
DeitelMessenger
NonBlockingServ
er.java
Lines 134-135
Linesthe
144-147
Register
new client
with the selector
} // end if key.isAcceptable
else if ( key.isReadable() ) {
// ready for read
// get socketChannel ready for read
SocketChannel socketChannel =
( SocketChannel ) key.channel();
Get a readable channel
and read the message
from it
readMessage( socketChannel );
}
} // end processing each channel
 2003 Prentice Hall, Inc.
All rights reserved.
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
} // end processing incoming requests
} // end method getConnection
// send message to client
private void writeMessage( String message ) throws IOException
{
Socket socket;
SocketChannel socketChannel;
Outline
DeitelMessenger
NonBlockingServ
er.java
Lines 171 and 174
// echo message back to all connected clients
for ( int i = 0; i < sockets.size(); i++ ) {
socket = ( Socket ) sockets.elementAt( i );
socketChannel = socket.getChannel();
// send message to client
try {
// convert message to bytes in charSet
writeBuffer = charSet.encode( message );
// write message to socketChannel
socketChannel.write( writeBuffer );
Encode the message
and send it to the client
}
 2003 Prentice Hall, Inc.
All rights reserved.
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
// process problems sending object
catch ( IOException ioException ) {
ioException.printStackTrace();
socketChannel.close();
sockets.remove( socket );
}
Outline
DeitelMessenger
Close the client
NonBlockingServ
channel and remove
it
er.java
from the selector
} // end for
} // end method writeMessage
// read message from client
private void readMessage( SocketChannel socketChannel )
throws IOException
{
// read message
try {
if ( socketChannel.isOpen() ) {
readBuffer.clear();
socketChannel.read( readBuffer );
readBuffer.flip();
CharBuffer charMessage = charSet.decode( readBuffer );
String message = charMessage.toString().trim();
Lines 180-181
Line 197
Line 198
Read the message from
the client
Flip the buffer
 2003 Prentice Hall, Inc.
All rights reserved.
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
Outline
// remove and close the connection when client disconnects
if ( message.indexOf( "Disconnect" ) >= 0 ) {
sockets.remove( socketChannel.socket() );
DeitelMessenger
Close the client
socketChannel.close();
NonBlockingServ
channel and remove
it
}
er.java
from the selector
else
writeMessage( message );
Line 205
} // end if
} // end try
catch ( IOException ioException ) {
ioException.printStackTrace();
sockets.remove( socketChannel.socket() );
socketChannel.close();
}
Lines 216-217
Close the client
channel and remove it
from the selector
} // end method readMessage
 2003 Prentice Hall, Inc.
All rights reserved.
222
223
224
225
226
227
228
229 }
public static void main( String args[] )
{
DeitelMessengerNonBlockingServer application =
new DeitelMessengerNonBlockingServer();
application.runServer();
}
Outline
DeitelMessenger
NonBlockingServ
er.java
// end class DeitelMessengerNonBlockingServer
 2003 Prentice Hall, Inc.
All rights reserved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Fig. 18.23: SocketMessageManager2.java
// SocketMessageManager2 is a class for objects capable of managing
// communications with a message server.
package com.deitel.messenger.sockets.client;
import
import
import
import
import
import
java.io.*;
java.nio.*;
java.nio.channels.*;
java.nio.charset.*;
java.net.*;
java.util.*;
Outline
SocketMessageMa
nager2.java
import com.deitel.messenger.*;
public class SocketMessageManager2 implements MessageManager {
private SocketChannel socketChannel;
private MessageListener messageListener;
private String serverAddress;
private ReceivingThread receiveMessage;
private boolean connected;
private Charset charSet = Charset.forName( "UTF-8" );
private ByteBuffer writeBuffer;
private ByteBuffer readBuffer = ByteBuffer.allocate( 512 );
 2003 Prentice Hall, Inc.
All rights reserved.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Outline
public SocketMessageManager2( String host )
{
serverAddress = host;
connected = false;
}
SocketMessageMa
nager2.java
// connect to message server and start receiving message
public void connect( MessageListener listener )
{
messageListener = listener;
Line 40
Line 46
// connect to server and start thread to receive message
try {
Create Socket to
communicate with
DeitelMessengerServer
// create SocketChannel to make connection to server
socketChannel = SocketChannel.open();
socketChannel.connect( new InetSocketAddress(
InetAddress.getByName( serverAddress ), 12345 ) );
// start ReceivingThread to receive messages sent by server
receiveMessage = new ReceivingThread();
receiveMessage.start();
connected = true;
}
Start Thread that listens
for incoming messages
 2003 Prentice Hall, Inc.
All rights reserved.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
catch ( Exception exception ) {
exception.printStackTrace();
}
}
// disconnect from message server and stop receiving message
public void disconnect( MessageListener listener )
{
if ( connected ) {
Outline
SocketMessageMa
nager2.java
Line 67
// send disconnect request and stop receiving
try {
sendMessage( "", "Disconnect" );
connected = false;
// send interrupt signal to receiving thread
receiveMessage.interrupt();
Interrupt the receiving thread
}
catch ( Exception exception ) {
exception.printStackTrace();
}
}
}
 2003 Prentice Hall, Inc.
All rights reserved.
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
// send message to message server
public void sendMessage( String userName, String messageBody )
{
String message = userName + "> " + messageBody;
// send message to server
try {
writeBuffer = charSet.encode( message );
socketChannel.write( writeBuffer );
}
catch ( IOException ioException ) {
ioException.printStackTrace();
Outline
SocketMessageMa
nager2.java
Line 83
Encode the message
and send it to the client
try {
socketChannel.close();
}
catch ( IOException exception ) {
exception.printStackTrace();
}
}
} // end method sendMessage
public class ReceivingThread extends Thread
{
 2003 Prentice Hall, Inc.
All rights reserved.
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
public void run()
{
int messageLength = 0;
String message = "";
SocketMessageMa
nager2.java
// read messages until server close the connection
try {
// process messages sent from server
do {
readBuffer.clear();
socketChannel.read( readBuffer );
readBuffer.flip();
CharBuffer charMessage = charSet.decode( readBuffer );
message = charMessage.toString().trim();
Line 111
Read the message from
the 112
client
Line
Flip the buffer
// tokenize message to retrieve user name and message body
StringTokenizer tokenizer =
new StringTokenizer( message, ">" );
// ignore messages that do not contain a user
// name and message body
if ( tokenizer.countTokens() == 2 )
 2003 Prentice Hall, Inc.
All rights reserved.
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
// send message to MessageListener
messageListener.messageReceived(
tokenizer.nextToken(),
// user name
tokenizer.nextToken() ); // message body
} while ( true );
// keep receiving messages
Outline
SocketMessageMa
nager2.java
} // end try
// catch problems reading from server
catch ( IOException ioException ) {
if ( ioException instanceof ClosedByInterruptException )
System.out.println( "socket channel closed" );
else {
ioException.printStackTrace();
try {
socketChannel.close();
System.out.println( "socket channel closed" );
}
catch ( IOException exception ) {
exception.printStackTrace();
}
}
 2003 Prentice Hall, Inc.
All rights reserved.
149
} // end catch
150
151
} // end method run
152
153
} // end inner class ReceivingThread
154
155 } // end class SocketMessageManager2
Outline
SocketMessageMa
nager2.java
 2003 Prentice Hall, Inc.
All rights reserved.
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
// Fig. 18.24: DeitelMessenger2.java
// DeitelMessenger2 is a chat application that uses a ClientGUI
// to communicate with chat server.
package com.deitel.messenger.sockets.client;
import com.deitel.messenger.*;
Outline
DeitelMessenger
2.java
public class DeitelMessenger2 {
public static void main( String args[] )
{
MessageManager messageManager;
// create new DeitelMessenger
if ( args.length == 0 )
messageManager = new SocketMessageManager2( "localhost" );
else
messageManager = new SocketMessageManager2( args[ 0 ] );
// create GUI for SocketMessageManager
ClientGUI clientGUI = new ClientGUI( messageManager );
clientGUI.setSize( 300, 400 );
clientGUI.setResizable( false );
clientGUI.setVisible( true );
}
} // end class DeitelMessenger2
 2003 Prentice Hall, Inc.
All rights reserved.
18.12.1 Creational Design Patterns
• Abstract Factory design pattern
– Creational design pattern
– System determines subclass from which to instantiate
objects at runtime
– Uses a factory object
• Uses an interface to instantiate object
– Example:
• java.net.SocketFactory creates SocketImpl object
 2003 Prentice Hall, Inc. All rights reserved.
18.12.2 Structural Design Patterns
• Decorator design pattern
– Structural design pattern
– Allows object to gain additional responsibilities dynamically
– Example:
• ObjectOutputStream writes objects to streams (bytes)
• FileOutputStream writes bytes to files
• We can “decorate” the FileOutputStream with
ObjectOutputStream to write objects to files:
output = new ObjectOutputStream(
new FileOutputStream( fileName ) );
 2003 Prentice Hall, Inc. All rights reserved.
18.12.2 Structural Design Patterns
• Facade design pattern
– Structural design pattern
– Allows one object to represent a subsystem
– Example:
• Gas pedal is facade object for car’s acceleration subsystem
• java.net.URL is a facade object
– Can access InetAddress and URLStreamHandler
objects through facade
 2003 Prentice Hall, Inc. All rights reserved.
18.12.3 Architectural Patterns
• Architectural patterns
– Promote loose coupling among subsystems
– Specify all subsystems and how they interact with each other
 2003 Prentice Hall, Inc. All rights reserved.
18.12.3 Architectural Patterns
• Model-View-Controller architectural pattern
– Model
• Contains application data
– View
• Graphical representation of model
– Controller
• Input-processing logic
 2003 Prentice Hall, Inc. All rights reserved.
Fig. 18.25 Model-View-Controller Architecture
modifies
Controller
 2003 Prentice Hall, Inc. All rights reserved.
notifies
Model
View
18.12.3 Architectural Patterns
• Layers architectural pattern
– Divide system functionality into separate layers
• Each layer contains a set of system responsibilities
• Designers can modify layer without having to modify others
– Example:
• Three-tier architecture
– Information tier maintains application data (via database)
– Middle tier handles business logic
– Client tier provides user interface
 2003 Prentice Hall, Inc. All rights reserved.
Fig. 18.26 Three-tier application model
Client tier
(Top tier)
Middle tier
Application
Information tier
(Bottom tier)
Database
 2003 Prentice Hall, Inc. All rights reserved.