Socket

Networking
Introduction
• In this chapter
– Socket-based communications
• View networking like file I/O
– Stream sockets
• When connection in place, data flows in continuous streams
• TCP protocol
• Preferred
Establishing a Simple Server (Using Stream
Sockets)
• Creating a Java server
– Create ServerSocket object
ServerSocket s = new ServerSocket( port,
queueLength );
• Register port number and set max number of waiting clients
• Binds server to port, waits for clients
– Server listens indefinitely (blocks) for clients
Socket connection = s.accept()
• Connections managed by Socket objects
• Returns Socket when connection established
Establishing a Simple Client (Using Stream
Sockets)
• Creating a Java server
– Get I/O objects for communication
• OutputStream - sends info to client
• InputStream - gets info from client
• Server's input stream is client's output stream, and vice versa
– Use Socket object to get references to streams
• connection.getInputStream()
• connection.getOutputStream()
– Methods write and read
• Send individual bytes
Establishing a Simple Client (Using Stream
Sockets)
• Creating a Java server
– Chaining stream types (sending objects and data, not bytes)
ObjectInputStream input = new ObjectInputStream(
connection.getInputStream() )
– Processing phase
• Server/client communicate using InputStream and
OutputStream
– Termination
• Transmission complete
• Method close (of Socket)
connection.close()
– Networking appears as sequential file I/O
• Sockets simplify networking
Establishing a Simple Client (Using Stream
Sockets)
• Creating a Java client
– Create Socket to connect to server
Socket connection = new Socket(
serverAddress, port )
• If successful, returns Socket
– Else throws subclass of IOException
– Get stream objects
• connection.getInputStream()
• connection.getOutputStream()
• Use chaining if transmitting objects and data, not pure bytes
– ObjectInputStream, ObjectOutputStream
Establishing a Simple Client (Using Stream
Sockets)
• Creating a Java client
– Processing phase
• Communicate using stream objects
– Termination
• Transmission complete
• connection.close() (close Socket)
– Client must determine when server done
• read returns -1 when eof found
• ObjectInputStream generates EOFException
Client/Server Interaction with Stream Socket
Connections
• Upcoming program
– Simple client/server chat application
– Use stream sockets
– Client connects, transmit String objects
• do-while loop to get input
• Event handler calls sendData method to send output
– When either sends TERMINATE, connection terminates
• Server waits for next client
– GUI:
Client/Server Interaction with Stream Socket
Connections
• Server
60
connection.getInetAddress().getHostName() );
– Once connection (Socket) established
• getInetAddress() - returns InetAddress object
• getHostName() - returns client's host name
63
64
65
output = new ObjectOutputStream(
connection.getOutputStream() );
output.flush();
– Create ObjectOutputStream
• flush()
– Sends stream header to client
– Required by client's ObjectInputStream
Client/Server Interaction with Stream Socket
Connections
108
109
111
112
113
private void sendData( String s )
{
output.writeObject( "SERVER>>> " + s );
output.flush();
display.append( "\nSERVER>>>" + s );
– Send/receive data
• Method sendData called by event handler
• Buffer flushed after every transmission
81
82
display.setCaretPosition(
display.getText().length() );
– Sets cursor position to end of text
• Allows JTextArea to scroll with text
– Server processes single connection at a time
• More likely to have separate threads for each connection
1
// Fig. 21.3: Server.java
2
// Set up a Server that will receive a connection
3
// from a client, send a string to the client,
4 // and close the connection.
5
import java.io.*;
6
import java.net.*;
7
import java.awt.*;
8
import java.awt.event.*;
9 import javax.swing.*;
10
11 public class Server extends JFrame {
12
private JTextField enter;
13
private JTextArea display;
14
ObjectOutputStream output;
15
ObjectInputStream input;
16
17
public Server()
18
{
19
super( "Server" );
20
21
Container c = getContentPane();
22
23
enter = new JTextField();
24
enter.setEnabled( false );
1. Constructor
1.1 GUI components
25
enter.addActionListener(
26
new ActionListener() {
27
public void actionPerformed( ActionEvent e )
28
29
{
30
}
sendData( e.getActionCommand() );
31
}
32
);
33
34
c.add( enter, BorderLayout.NORTH );
35
display = new JTextArea();
36
c.add( new JScrollPane( display ),
37
1.2 Event handler
The event handlers1.3
calls
method
GUI
sendData, using text in
JTextField as argument.
2. Method runServer
2.1 ServerSocket
BorderLayout.CENTER );
38
39
40
41
setSize( 300, 150 );
show();
}
42
43
public void runServer()
44
{
45
ServerSocket server;
46
Socket connection;
47
int counter = 1;
Register port 5000, server will allow
100 clients to wait in queue.
48
49
50
51
52
try {
// Step 1: Create a ServerSocket.
server = new ServerSocket( 5000, 100 );
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
79
80
81
82
83
while ( true ) {
// Step 2: Wait for a connection. Infinite loop to wait for
connections
display.setText( "Waiting for connection\n"
); from clients.
connection = server.accept();
display.append( "Connection " + counter +
" received from: " +
connection.getInetAddress().getHostName() );
// Step 3: Get input and output streams.
output = new ObjectOutputStream(
connection.getOutputStream() );
output.flush();
input = new ObjectInputStream(
connection.getInputStream() );
display.append( "\nGot I/O streams\n" );
// Step 4: Process connection.
String message =
"SERVER>>> Connection successful";
output.writeObject( message );
output.flush();
enter.setEnabled( true );
2.2 accept
Wait for connection
(server.accept() waits
2.3 getHostName
indefinitely).
2.4 Get streams
Display host location.
2.5 writeObject
Set up I/O streams, flush
buffer (sends stream data).
2.6 Loop
Send confirmation
message.
Loop to get input.
Set cursor to end
of text.
do {
try {
message = (String) input.readObject();
display.append( "\n" + message );
display.setCaretPosition(
display.getText().length() );
}
84
85
86
87
88
);
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
catch ( ClassNotFoundException cnfex ) {
display.append(
"\nUnknown object type received" );
}
} while ( !message.equals( "CLIENT>>> TERMINATE" )
// Step 5: Close connection.
display.append( "\nUser terminated connection" );
enter.setEnabled( false );
output.close();
Close connection
input.close();
connection.close();
Loop until TERMINATE
string sent.
2.6 Loop
2.7 close
and I/O3.streams.
Method sendData
3.1 writeObject
++counter;
}
}
3.2 flush
catch ( EOFException eof ) {
System.out.println( "Client terminated connection" );
}
catch ( IOException io ) {
Send String object to client. Flush
io.printStackTrace();
}
buffer to ensure it is sent, and update
}
server's display.
private void sendData( String s )
{
try {
output.writeObject( "SERVER>>> " + s );
output.flush();
display.append( "\nSERVER>>>" + s );
}
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
catch ( IOException cnfex ) {
display.append(
"\nError writing object" );
}
public static void main( String args[] )
{
Server app = new Server();
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
134
135
136 }
4. main
}
app.runServer();
}
Client/Server Interaction with Stream Socket
Connections
• Client
– Similar to server
– Creates same GUI
– Loops to wait for input
• Sends output through event handler and sendData
Client/Server Interaction with Stream Socket
Connections
50
51
client = new Socket(
InetAddress.getByName( "127.0.0.1" ), 5000 );
– Create Socket with two arguments
• Internet address of server and port number
– static method getByName (Class InetAddress)
• Returns InetAddress object
• Takes String
• Could have taken "localhost" or called static method
getLocalHost
– Create I/O objects as before
• Output of server is input of client
1
// Fig. 21.4: Client.java
2
// Set up a Client that will read information sent
3
// from a Server and display the information.
4 import java.io.*;
5
import java.net.*;
6
import java.awt.*;
7
import java.awt.event.*;
8
import javax.swing.*;
9
10 public class Client extends JFrame {
11
private JTextField enter;
12
private JTextArea display;
13
ObjectOutputStream output;
14
ObjectInputStream input;
15
String message = "";
16
17
public Client()
18
{
19
super( "Client" );
20
21
Container c = getContentPane();
22
23
enter = new JTextField();
24
enter.setEnabled( false );
1. Constructor
1.1 GUI
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
51
52
53
54
55
enter.addActionListener(
new ActionListener() {
public void actionPerformed( ActionEvent e )
{
sendData( e.getActionCommand() );
}
}
);
Client gets
c.add( enter, BorderLayout.NORTH );
1.2 Event handler
1.3 GUI
text from JTextField
and calls sendData.
2. Method runClient
display = new JTextArea();
c.add( new JScrollPane( display ),
BorderLayout.CENTER );
2.1 Socket
setSize( 300, 150 );
show();
}
public void runClient()
{
Socket client;
Create Socket to server,
make connection.
try {
// Step 1: Create a Socket to make connection.
display.setText( "Attempting connection\n" );
client = new Socket(
InetAddress.getByName( "127.0.0.1" ), 5000 );
56
57
display.append( "Connected to: " +
client.getInetAddress().getHostName() );
58
59
// Step 2: Get the input and output streams.
60
output = new ObjectOutputStream(
61
client.getOutputStream() );
62
output.flush();
63
input = new ObjectInputStream(
64
display.append( "\nGot I/O streams\n" );
66
67
// Step 3: Process connection.
68
enter.setEnabled( true );
69
71
2.3 flush
client.getInputStream() );
65
70
do {
2.4 Loop
Code similar to server. Create
I/O objects, flush buffer, loop to
wait for and process input.
try {
72
message = (String) input.readObject();
73
display.append( "\n" + message );
74
display.setCaretPosition(
75
display.getText().length() );
76
}
77
catch ( ClassNotFoundException cnfex ) {
78
display.append(
79
80
81
82
2.2 I/O streams
"\nUnknown object type received" );
}
} while ( !message.equals( "SERVER>>> TERMINATE" ) );
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Step 4: Close connection.
display.append( "Closing connection.\n" );
input.close();
output.close();
client.close();
}
catch ( EOFException eof ) {
System.out.println( "Server terminated connection" );
}
catch ( IOException e ) {
e.printStackTrace();
}
}
private void sendData( String s )
{
try {
message = s;
101
output.writeObject( "CLIENT>>> " + s );
102
output.flush();
103
display.append( "\nCLIENT>>>" + s );
104
}
105
catch ( IOException cnfex ) {
106
display.append(
107
"\nError writing object" );
108
109
110
}
}
2.5 close
3. Method sendData
111
public static void main( String args[] )
112
{
113
Client app = new Client();
114
115
app.addWindowListener(
116
4. main
new WindowAdapter() {
117
public void windowClosing( WindowEvent e )
118
{
119
System.exit( 0 );
120
}
121
}
122
);
123
124
125
app.runClient();
}
126 }
127
Program Output
Program
Output
Connectionless Client/Server Interaction
with Datagrams
• Connection-oriented interaction
– Like phone call
• Have connection to other end
• Connection maintained for duration of call, even if not talking
• Connectionless interaction
– Like sending postal mail
– Use datagrams, packets of data
– If large packet, break into smaller pieces
• Send separately
• May arrive out of order or not arrive at all
• Duplicates may arrive
Connectionless Client/Server Interaction
with Datagrams
27
socket = new DatagramSocket( 5000 );
– DatagramSocket( port )
• Binds server to port
40
41
42
byte data[] = new byte[ 100 ];
receivePacket =
new DatagramPacket( data, data.length );
– DatagramPacket( byteArray,
byteArray.length )
• Create DatagramPacket to store received packet
• byteArray stores data
45
socket.receive( receivePacket );
– Method receive( packetToStore )
• Blocks until packet arrives, stores in packetToStore
Connectionless Client/Server Interaction
with Datagrams
48
49
50
51
52
53
54
display.append( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
"\nHost port: " + receivePacket.getPort() +
"\nLength: " + receivePacket.getLength() +
"\nContaining:\n\t" +
new String( receivePacket.getData(), 0,
receivePacket.getLength() ) );
– getAddress - returns InetAddress
– getPort, getLength - return integers
– getData - returns byte array
• Used in String constructor to create string
Connectionless Client/Server Interaction
with Datagrams
58
59
60
sendPacket =
new DatagramPacket( receivePacket.getData(),
receivePacket.getLength(),
61
receivePacket.getAddress(),
62
receivePacket.getPort() );
63
socket.send( sendPacket );
– Echo packet back to client
• DatagramPacket( byteArray, length,
InetAddress, port )
• Method send( packetToSend )
1 // Fig. 21.5: Server.java
2 // Set up a Server that will receive packets from a
3
4
5
// client and send packets to a client.
import java.io.*;
import java.net.*;
1. Declarations
6 import java.awt.*;
7 import java.awt.event.*;
8 import javax.swing.*;
9
1.1 DatagramSocket
10 public class Server extends JFrame {
11
private JTextArea display;
12
13
private DatagramPacket sendPacket, receivePacket;
14
private DatagramSocket socket;
15
16
17
18
19
20
21
22
public Server()
{
super( "Server" );
display = new JTextArea();
getContentPane().add( new JScrollPane( display),
BorderLayout.CENTER );
23
setSize( 400, 300 );
24
25
26
27
28
show();
try {
socket = new DatagramSocket( 5000 );
}
Create new DatagramSocket,
binds server to port.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
catch( SocketException se ) {
se.printStackTrace();
System.exit( 1 );
Loop
}
to wait for packets.
}
public void waitForPackets()
{
Create new DatagramPacket
while ( true ) {
to receive info.
try {
// set up packet
byte data[] = new byte[ 100 ];
receivePacket =
new DatagramPacket( data, data.length );
2. Method
waitForPackets
2.1 receivePacket
2.2 receive
2.3 Process packet
// wait for packet
socket.receive( receivePacket );
Gather and display
packetpacket
data.
2.4 Echo
Convert byte array to a String.
// process packet
display.append( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
"\nHost port: " + receivePacket.getPort() +
"\nLength: " + receivePacket.getLength() +
"\nContaining:\n\t" +
new String( receivePacket.getData(), 0,
receivePacket.getLength() ) );
// echo information from packet back to client
display.append( "\n\nEcho data to client...");
sendPacket =
new DatagramPacket( receivePacket.getData(),
Create packet back to client.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 }
receivePacket.getLength(),
receivePacket.getAddress(),
receivePacket.getPort() );
socket.send( sendPacket );
Send packet
display.append( "Packet sent\n" );
display.setCaretPosition(
display.getText().length() );
}
catch( IOException io ) {
display.append( io.toString() + "\n" );
io.printStackTrace();
}
}
}
public static void main( String args[] )
{
Server app = new Server();
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
app.waitForPackets();
}
back to client.
2.5 send
3. main
Program Output
Connectionless Client/Server Interaction
with Datagrams
• Client
– Similar to server
– Has JTextField
• Sends packets with event handler for JTextField
• Convert String to byteArray
– String.getBytes()
– Have loop to receive echoed packets from server
31
socket = new DatagramSocket();
– Constructor needs no arguments
• Uses next available port
• Server gets client's port number as part of DatagramPacket
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Fig. 21.6: Client.java
// Set up a Client that will send packets to a
// server and receive packets from a server.
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Client extends JFrame implements ActionListener {
private JTextField enter;
private JTextArea display;
private DatagramPacket sendPacket, receivePacket;
private DatagramSocket socket;
public Client()
{
super( "Client" );
enter = new JTextField( "Type message here" );
enter.addActionListener( this );
getContentPane().add( enter, BorderLayout.NORTH );
display = new JTextArea();
getContentPane().add( new JScrollPane( display ),
BorderLayout.CENTER );
setSize( 400, 300 );
show();
1. Constructor
1.1 GUI
1.2 Register event
handler
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
try {
socket = new DatagramSocket();
}
catch( SocketException se ) {
se.printStackTrace();
System.exit( 1 );
}
No argument constructor.
}
public void waitForPackets()
Similar to server, loop to
{
receive echoed packets.
while ( true ) {
try {
// set up packet
byte data[] = new byte[ 100 ];
receivePacket =
new DatagramPacket( data, data.length );
// wait for packet
socket.receive( receivePacket );
// process packet
display.append( "\nPacket received:" +
"\nFrom host: " + receivePacket.getAddress() +
"\nHost port: " + receivePacket.getPort() +
"\nLength: " + receivePacket.getLength() +
"\nContaining:\n\t" +
new String( receivePacket.getData(), 0,
receivePacket.getLength() ) );
1.3 DatagramSocket
2. waitForPackets
2.1 DatagramPacket
2.2 receive
2.3 Process packet
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
display.setCaretPosition(
display.getText().length() );
}
catch( IOException exception ) {
display.append( exception.toString() + "\n" );
exception.printStackTrace();
}
}
3. actionPerformed
3.1 Create packet
}
public void actionPerformed( ActionEvent e )
3.2 send
{
try {
Convert String to a byte array,
display.append( "\nSending packet containing: " +
initialize
e.getActionCommand() + "\n"
); DatagramPacket.
String s = e.getActionCommand();
byte data[] = s.getBytes();
sendPacket = new DatagramPacket( data, data.length,
InetAddress.getLocalHost(), 5000 );
socket.send( sendPacket );
display.append( "Packet sent\n" );
display.setCaretPosition(
display.getText().length() );
}
catch ( IOException exception ) {
display.append( exception.toString() + "\n" );
exception.printStackTrace();
}
}
use to
91
92
93
94
95
96
97
98
99
100
public static void main( String args[] )
{
Client app = new Client();
app.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
101
}
102
}
103
);
104
105
106
app.waitForPackets();
}
107 }
Program Output
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
• Tic-Tac-Toe
– Create application allowing two clients to connect to server
• When each client connects
– Player object created in separate thread
– Manages connection
– Server maintains board information
• Byte array represents board
• Determines if moves are valid
– Each client has own GUI
• Has board information
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
29
50
52
53
54
server = new ServerSocket( 5000, 2 );
for ( int i = 0; i < players.length; i++ ) {
players[ i ] =
new Player( server.accept(), this, i );
players[ i ].start();
– Server creates ServerSocket
• Waits for two connections, creates two Player objects
139class Player extends Thread {
148
public Player( Socket s, TicTacToeServer t, int num )
152
connection = s;
165
166
control = t;
number = num;
– Initialize Player objects
• Connection to respective client, reference to server, number
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
183
control.display( "Player " +
184
( number == 0 ? 'X' : 'O' ) + " connected" );
185
output.writeChar( mark );
– Update server (display) and send client their mark (X or O)
178
192
196
197
public void run()
if ( mark == 'X' ) {
synchronized( this ) {
while ( threadSuspended )
198
wait();
– Suspend Player X
64
65
66
synchronized ( players[ 0 ] ) {
players[ 0 ].threadSuspended = false;
players[ 0 ].notify();
• Notify Player X after Player O connects
• Code comes after loop to initialize both Players
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
• Game begins playing
– run method executes while loop
210
211
213
)
{
214
215
while ( !done ) {
int location = input.readInt();
if ( control.validMove( location, number )
control.display( "loc: " + location );
output.writeUTF( "Valid move." );
– Read integer representing move from client
• Test if valid (control.validMove)
• If so, send message to server and client
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
79
80
public synchronized boolean validMove( int loc,
int player )
– Method validMove
• synchronized - one move at a time
86
88
while ( player != currentPlayer ) {
wait();
– If player not currentPlayer, put in wait state
• When other player moves, notify
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
95
96
if ( !isOccupied( loc ) ) {
board[ loc ] =
97
98
(byte) ( currentPlayer == 0 ? 'X' : 'O' );
currentPlayer = ( currentPlayer + 1 ) % 2;
99
100
101
players[ currentPlayer ].otherPlayerMoved( loc );
notify();
// tell waiting player to continue
return true;
– Checks if location occupied
• If not, updates byte array, currentPlayer
• otherPlayerMoved - informs other client of move
• Notify waiting client
• Return true (valid move)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Fig. 21.7: 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.*;
public class TicTacToeServer extends JFrame {
private byte board[];
private boolean xMove;
Use nine element byte array
private JTextArea output;
represent board. Create
private Player players[];
Player array.
private ServerSocket server;
private int currentPlayer;
public TicTacToeServer()
{
super( "Tic-Tac-Toe Server" );
board = new byte[ 9 ];
xMove = true;
players = new Player[ 2 ];
currentPlayer = 0;
1. Constructor
1.1 Initialization
1.2 ServerSocket
to
Server creates ServerSocket
to get connections.
// set up ServerSocket
try {
server = new ServerSocket( 5000, 2 );
}
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
catch( IOException e ) {
e.printStackTrace();
System.exit( 1 );
}
1.3 GUI
2. Method execute
output = new JTextArea();
getContentPane().add( output, BorderLayout.CENTER );
output.setText( "Server awaiting connections\n" );
2.1 Initialize players
setSize( 300, 300 );
show();
}
// wait for two connections so game can be played
public void execute()
{
for ( int i = 0; i < players.length; i++ ) {
try {
players[ i ] =
new Player( server.accept(), this, i );
players[ i ].start();
}
catch( IOException e ) {
e.printStackTrace();
System.exit( 1 );
}
}
Initialize Player objects with
client connection. Player X begins
in wait state.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Player X is suspended until Player O connects.
// Resume player X now.
synchronized ( players[ 0 ] ) {
players[ 0 ].threadSuspended = false;
players[ 0 ].notify();
}
Notify player X to resume execution.
2.2 notify player X
3. Method display
}
public void display( String s )
{
output.append( s + "\n" );
}
Allow only
4. Method validMove
(synchronized)
one move at a time.
// Determine if a move is valid.
// This method is synchronized because only one move can be
// made at a time.
public synchronized boolean validMove( int loc,
int player )
{
boolean moveDone = false;
while ( player != currentPlayer ) {
try {
wait();
}
If player is not the current
player, send to wait state.
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
catch( InterruptedException e ) {
e.printStackTrace();
}
}
If location unoccupied, update current
player, inform other player4.1
of move,
board,
Update
information
and notify waiting players.
if ( !isOccupied( loc ) ) {
board[ loc ] =
(byte) ( currentPlayer == 0 ? 'X' : 'O' );
currentPlayer = ( currentPlayer + 1 ) % 2;
players[ currentPlayer ].otherPlayerMoved( loc );
notify();
// tell waiting player to continue
return true;
}
else
return false;
}
public boolean isOccupied( int loc )
{
if ( board[ loc ] == 'X' || board [ loc ] == 'O' )
return true;
else
return false;
}
public boolean gameOver()
{
// Place code here to test for a winner of the game
return false;
}
5. isOccupied
6. gameOver
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
public static void main( String args[] )
{
TicTacToeServer game = new TicTacToeServer();
game.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
game.execute();
}
135 }
136
137
138 // Player class to manage each Player as a thread
139 class Player extends Thread {
140
private Socket connection;
141
private DataInputStream input;
142
private DataOutputStream output;
143
private TicTacToeServer control;
144
private int number;
145
private char mark;
146
protected boolean threadSuspended = true;
147
7. main
8. Class Player
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
public Player( Socket s, TicTacToeServer t, int num )
{
mark = ( num == 0 ? 'X' : 'O' );
connection = s;
Initialize with client8.1 Constructor
connection, reference to server
object, and player number.
8.2 I/O streams
try {
input = new DataInputStream(
connection.getInputStream() );
output = new DataOutputStream(
connection.getOutputStream() );
}
catch( IOException e ) {
e.printStackTrace();
System.exit( 1 );
}
8.3
otherPlayerMoved
control = t;
number = num;
}
Inform Player of other's move.
public void otherPlayerMoved( int loc )
{
try {
output.writeUTF( "Opponent moved" );
output.writeInt( loc );
}
catch ( IOException e ) { e.printStackTrace(); }
}
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
public void run()
{
boolean done = false;
Server displays connected
client. Mark (X or O) sent to
client.
try {
control.display( "Player " +
( number == 0 ? 'X' : 'O' ) + " connected" );
output.writeChar( mark );
output.writeUTF( "Player " +
( number == 0 ? "X connected\n" :
"O connected, please wait\n" ) );
// wait for another player to arrive
if ( mark == 'X' ) {
output.writeUTF( "Waiting for another player" );
try {
synchronized( this ) {
while ( threadSuspended )
wait();
}
}
catch ( InterruptedException e ) {
e.printStackTrace();
}
8.4.1 Inform server
8.4.2 Send mark
8.4.3 Player X waits
Player X waits (so Player O can
connect). Once Player O
connects, X can move.
output.writeUTF(
"Other player connected. Your move." );
}
8.4 run
209
// Play game
210
while ( !done ) {
211
int location = input.readInt();
212
213
if ( control.validMove( location, number ) ) {
214
control.display( "loc: " + location );
215
output.writeUTF( "Valid move." );
216
}
217
else
218
8.5 Loop for input
8.6 validMove
output.writeUTF( "Invalid move, try again" );
219
220
if ( control.gameOver() )
221
done = true;
222
}
223
224
connection.close();
225
}
226
catch( IOException e ) {
227
e.printStackTrace();
228
System.exit( 1 );
229
230
231 }
}
}
Loop and get input. Check validity, and
inform server and client.
Program Output
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
• Client
– Creates GUI
• Uses nine Square objects (extend JPanel)
– start method
• Connects to server
• Gets I/O streams
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
11public class TicTacToeClient extends JApplet
12
implements Runnable {
85
outputThread = new Thread( this );
86
outputThread.start();
– Implements interface Runnable, so separate thread can
execute read input
• Executes run method, which loops and reads input
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
94
95
98
107
109
110
114
public void run()
{
myMark = input.readChar();
while ( true ) {
String s = input.readUTF();
processMessage( s );
}
– Method run handles input
• Sets player's mark
• Loops, gets input, calls processMessage
Client/Server Tic-Tac-Toe Using a
Multithreaded Server
119
121
121
public void processMessage( String s )
if ( s.equals( "Valid move." ) ) {
if ( s.equals( "Valid move." ) ) {
122
display.append( "Valid move, please wait.\n" );
123
currentSquare.setMark( myMark );
124
currentSquare.repaint();
125
}
126
130
else if ( s.equals( "Invalid move, try again" ) ) {
else if ( s.equals( "Opponent moved" ) ) {
– Method processMessage
• Perform actions depending on String received
– Listen for MouseEvents
• If Square clicked, setCurrentSquare
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Fig. 21.8: TicTacToeClient.java
// Client for the TicTacToe program
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import javax.swing.*;
Allows applet to create a
thread, used to get input.
// Client class to let a user play Tic-Tac-Toe with
// another user across a network.
public class TicTacToeClient extends JApplet
implements Runnable {
private JTextField id;
private JTextArea display;
private JPanel boardPanel, panel2;
private Square board[][], currentSquare;
private Socket connection;
private DataInputStream input;
private DataOutputStream output;
private Thread outputThread;
private char myMark;
private boolean myTurn;
// Set up user-interface and board
public void init()
{
display = new JTextArea( 4, 30 );
display.setEditable( false );
getContentPane().add( new JScrollPane( display ),
BorderLayout.SOUTH );
1. implements
Runnable
1.1 Declarations
1.2 GUI
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
boardPanel = new JPanel();
GridLayout layout = new GridLayout( 3, 3, 0, 0 );
boardPanel.setLayout( layout );
1.3 GUI
board = new Square[ 3 ][ 3 ];
1.4 Event handlers
// 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 col = 0;
col < board[ row ].length; col++ ) {
Register event handlers
board[ row ][ col ] =
each Square.
new Square( ' ', row * 3 + col );
board[ row ][ col ].addMouseListener(
new SquareListener(
this, board[ row ][ col ] ) );
boardPanel.add( board[ row ][ col ] );
}
}
id = new JTextField();
id.setEditable( false );
for
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
getContentPane().add( id, BorderLayout.NORTH );
panel2 = new JPanel();
panel2.add( boardPanel, BorderLayout.CENTER );
getContentPane().add( panel2, BorderLayout.CENTER );
}
2. start
// Make connection to server and get associated streams.
2.1 Socket
// Start separate thread to allow this applet to
// continually update its output in text area display.
2.2 Thread
public void start()
Get connection to server.
{
try {
connection = new Socket(
InetAddress.getByName( "127.0.0.1" ), 5000 );
input = new DataInputStream(
connection.getInputStream() );
output = new DataOutputStream(
connection.getOutputStream() );
}
catch ( IOException e ) {
Create new thread, which
e.printStackTrace();
executes method run.
}
outputThread = new Thread( this );
outputThread.start();
}
92
93
// Control thread that allows continuous update of the
// text area display.
94
95
96
public void run()
{
// First get player's mark (X or O)
97
98
3. run
try {
myMark = input.readChar();
99
100
id.setText( "You are player \"" + myMark + "\"" );
myTurn = ( myMark == 'X' ? true : false );
101
102
103
}
catch ( IOException e ) {
e.printStackTrace();
104
105
106
}
107
108
while ( true ) {
try {
// Receive messages sent to client
109
110
111
String s = input.readUTF();
processMessage( s );
}
112
113
catch ( IOException e ) {
e.printStackTrace();
114
115
116
117
}
}
}
3.1 Get mark
3.2 Loop for input
Get player's mark (first data
sent) then loop for more input.
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Process messages sent to client
public void processMessage( String s )
{
if ( s.equals( "Valid move." ) ) {
display.append( "Valid move, please wait.\n" );
4. processMessage
currentSquare.setMark( myMark );
currentSquare.repaint();
4.1 setMark
}
else if ( s.equals( "Invalid move, try again" ) ) {
display.append( s + "\n" );
myTurn = true;
Process string. If valid move,
}
update current square with
else if ( s.equals( "Opponent moved" ) ) {
mark. If opponent moved,
try {
update appropriate square (in
int loc = input.readInt();
board array).
board[ loc / 3 ][ loc % 3 ].setMark(
( myMark == 'X' ? 'O' : 'X' ) );
board[ loc / 3 ][ loc % 3 ].repaint();
display.append(
"Opponent moved. Your turn.\n" );
myTurn = true;
}
catch ( IOException e ) {
e.printStackTrace();
}
}
147
else
148
display.append( s + "\n" );
149
150
display.setCaretPosition(
151
display.getText().length() );
152
}
153
154
public void sendClickedSquare( int loc )
155
{
156
if ( myTurn )
157
try {
158
output.writeInt( loc );
159
myTurn = false;
160
}
161
catch ( IOException ie ) {
162
ie.printStackTrace();
163
}
164
}
165
166
public void setCurrentSquare( Square s )
167
{
168
currentSquare = s;
169
}
170 }
171
172 // Maintains one square on the board
173 class Square extends JPanel {
174
private char mark;
175
private int location;
176
5.
sendClickedSquare
6. setCurrentSquare
7. Class Square
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
public Square( char m, int loc)
{
mark = m;
location = loc;
setSize ( 30, 30 );
198
public void paintComponent( Graphics g )
199
{
setVisible(true);
}
public Dimension getPreferredSize() {
return ( new Dimension( 30, 30 ) );
}
public Dimension getMinimumSize() {
return ( getPreferredSize() );
}
public void setMark( char c ) { mark = c; }
public int getSquareLocation() { return location; }
200
super.paintComponent( g );
201
g.drawRect( 0, 0, 29, 29 );
202
g.drawString( String.valueOf( mark ), 11, 20 );
203
204 }
}
7. Class Square
205
206 class SquareListener extends MouseAdapter {
207
private TicTacToeClient applet;
208
private Square square;
209
210
211
8. Event handler
public SquareListener( TicTacToeClient t, Square s )
{
212
applet = t;
213
square = s;
214
215
}
216
public void mouseReleased( MouseEvent e )
217
218
{
219
220
221 }
applet.setCurrentSquare( square );
applet.sendClickedSquare( square.getSquareLocation() );
}
Program
Output
Program
Output
Security and the Network
• Security
– Many Web browsers prevent file processing by applets (by
default)
• Malicious applets could be a security risk
• Applets can usually only talk with the machine that
downloaded it
• Trusted source
– Browsers can determine if applet came from trusted source
– If so, can be given more access