Creating a multithreaded Java Tic Tac Toe server
I have no experience with streams, unfortunately. I am doing a couple of "Hello World" examples that seem pretty easy. However, I need to enable streams in a Java Tic Tac Toe server that I have (which uses sockets). The design of my Tic Tac Toe game is as follows:
Provider.java
(server): Determines the current player, sends a text display / game board to the current player, determines if the game is over
Requester.java
(client): initiates the game board object for each client, keeps the client game in sync with the server game board, verifies the correct moves.
TBoard.java
: methods used by both client and server (make_move (), is_winner (), current_player (), etc.)
I was wondering if you guys can take a look at mine Provider.java
(server) and give me some advice on how to enable streams to play multiple games at the same time with tic tac toe ...
/**
* Provider.java
*
* @version 2.0
*/
import java.io.*;
import java.net.*;
/**
* The Provider class is responsible for any server-side activities with the
* Tic-Tac-Toe game. This includes:
*
* 1. Determining the current player 2. Managing the textual display for the two
* individual players 3. Updating the game board with the each player moves 4.
* Determine what player wins, if any
*/
public class Provider {
TBoard board = new TBoard(); // Instantiate the game board object
ServerSocket providerSocket;
Socket connection1 = null, connection2 = null;
ObjectOutputStream out, out2; // Client 1, Client 2
ObjectInputStream in, in2; // Client 1, Client 2
String message;
Boolean done = false;
String end = "";
int row, col, game_state = 3;
/**
* Class constructor.
*/
Provider() {
}
void run() {
try {
// Open a socket and wait for connections
providerSocket = new ServerSocket(20092);
System.out.println("Waiting for connection...");
connection1 = providerSocket.accept();
System.out.println("Connection received from Player 1 "
+ connection1.getInetAddress().getHostName());
connection2 = providerSocket.accept();
System.out.println("Connection received from Player 2 "
+ connection2.getInetAddress().getHostName());
out = new ObjectOutputStream(connection1.getOutputStream());
out2 = new ObjectOutputStream(connection2.getOutputStream());
in = new ObjectInputStream(connection1.getInputStream());
in2 = new ObjectInputStream(connection2.getInputStream());
do {
// Send the game game_state to the current player
sendInt(board.get_player(), game_state);
// If the game state != 3 (There is a winner or board is full)
if (game_state != 3) {
// Send game state to the other player
sendInt(board.get_opposite_player(), game_state);
done = true; // Condition to terminate the server
// If game is in "play" state
} else {
// Send both the current player and the Tic Tac Toe board
// (2D array) to current player
sendInt(board.get_player(), board.get_player());
send2D(board.get_player(), board.print_board());
sendString(board.get_player(),
"Please enter a row, press Enter, then enter a column: ");
// Receive the tic tac toe board from current player
// (after a move has been made)
if (board.get_player() == 1) {
int[][] c_array = (int[][]) in.readObject();
board.set_array(c_array);
} else {
int[][] c_array = (int[][]) in2.readObject();
board.set_array(c_array);
}
// Switch the current player
if (board.get_player() == 1) {
board.set_player(2);
} else {
board.set_player(1);
}
// If there is a winner, set the game state accordingly
if (board.winner() != 0) {
if (board.get_player() == 1) {
game_state = 2;
} else {
game_state = 1;
}
// If there is no winner and the board is full, set the
// game state accordingly
} else if (board.board_full() && board.winner() == 0) {
game_state = 0;
// Otherwise, stay in the "play" state
} else {
game_state = 3;
}
}
} while (done != true);
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
// Close the input/output streams, and the socket connections
try {
in.close();
out.close();
in2.close();
out2.close();
providerSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
/**
* Sends a String to the current client
*
* @param player the current player
* @param msg the String to be sent
*/
void sendString(int player, String msg) {
try {
if (player == 1) {
out.writeObject(msg);
out.flush();
} else {
out2.writeObject(msg);
out2.flush();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
/**
* Sends a String to the current client
*
* @param player the current player
* @param array the 2D array to be sent
*/
void send2D(int player, int[][] array) {
try {
if (player == 1) {
out.writeObject(array);
out.flush();
} else {
out2.writeObject(array);
out2.flush();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
/**
* Sends a int to the current client
*
* @param player the current player
* @param msg the int to be sent
*/
void sendInt(int player, int msg) {
try {
if (player == 1) {
out.writeObject(msg);
out.flush();
} else {
out2.writeObject(msg);
out2.flush();
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
/**
* Main method, invoking run() method
*/
public static void main(String args[]) {
Provider server = new Provider();
server.run();
}
}
Thank!
source to share
First, completely separate the actual Tic-Tac-Toe material from your communication level. Your communication layer should basically receive a message from any client, figure out which Tic-Tac-Toe instance belongs to that client, and then send the message. Likewise, a Tic-Tac-Toe instance may need to send a message to its players via the link layer.
I assume that your TicTacToe class will have a very simple API that looks like this:
public Result mark(int row, int col, int playerID);
Where Result can be something like VALID, INVALID_MOVE, PLAYER_WINS, or DRAW, or something like that. With an interface like this, you can easily create a single-player version of the game before moving on to online content.
In the end, you need 1 thread that exclusively calls serverSocket.await (), waits for 2 incoming connections, and then creates a new instance of Tic-Tac-Toe. Every time a message comes from one of these two clients, you send it to that particular instance. You need to somehow find the TicTacToe instance for the given socket, extract the message from the input stream, modify the TicTacToe instance, and then send the message back to the player 2 clients.
You will also need an additional stream for each individual socket connection. Every time you try to read from the socket input stream, you need to wait for some data to actually be sent from the client. This is where threads come into play.
Oh, by the way, the java.util.concurrent package provides ways to make your network server more scalable and efficient, but its quite complicated. Also, most of the ways to use it are actually single-threaded (in fact, it's actually more scalable for some reason, believe it or not). I recommend the cleaning pen for this assignment.
source to share