I'm currently developing a TicTacToe multithreaded networked game for my university and I'm stuck on an annoying problem.
I wish that my server accepts 2 connections each time and then waits for other 2 connections etc.
The problem is that, in my code, if a client connects to the server and closes the connection while the second client is not yet connected to the server, the second client is not able to play because it "thinks" that the first client is connected and ready.
I thought to do something like this but I can't find a way to actually implement it.
The server is structured in 3 classes:
TTT_Server (which cointains the main method and launches threads);
TTT_ServerThread (which contains the thread(s) behaviour);
TTT (which contains the TicTacToe board and some method).
TTT_Server class:
public class TTT_Server()
{
private static ServerSocket serverSocket;
private static boolean running = true;
public static void main(String[] args)
{
try
{
// creazione ServerSocket sulla porta 8089
serverSocket = new ServerSocket(8089);
System.out.println("Server Socket creata e in ascolto sulla porta 8089");
while(running)
{
TTT ttt = new TTT();
Socket socket1 = serverSocket.accept();
Socket socket2 = serverSocket.accept();
TTT_ServerThread st1 = new TTT_ServerThread(socket1, 1, ttt, socket2);
TTT_ServerThread st2 = new TTT_ServerThread(socket2, 2, ttt, socket1);
st1.start();
st2.start();
System.out.println("thread lanciati");
}
}
catch(IOException e)
{
System.out.println(e);
running = false;
}
finally
{
try
{
serverSocket.close();
}
catch (IOException e)
{
System.out.println(e);
}
}
}
}
(a part of) TTT_ServerThread class:
private Socket socket;
private Socket socketOtherPlayer;
private BufferedReader in;
private PrintWriter out;
private PrintWriter outOtherPlayer;
private TTT TicTacToe;
private int player;
private boolean fineGioco;
private int counter = 0;
public TTT_ServerThread(Socket socket, int num_connessione, TTT ttt, Socket socketOtherPlayer)
{
this.socket = socket;
this.socketOtherPlayer = socketOtherPlayer;
this.player = num_connessione;
this.TicTacToe = ttt;
try
{
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.out = new PrintWriter(socket.getOutputStream());
this.outOtherPlayer= new PrintWriter(socketOtherPlayer.getOutputStream());
}
catch(IOException e)
{
System.out.println(e);
}
}
#Override
public void run()
{
//[...]
}
(a part of) TTT class:
public class TTT
{
private int[] board = new int[9];
private int turno = 1;
public TTT()
{
for (int i = 0; i < 9; i++)
board[i] = 0;
}
protected synchronized void setBoard(int locazioneMossa, int giocatore)
{
board[locazioneMossa] = giocatore;
}
protected synchronized int getBoard(int locazioneMossa)
{
return board[locazioneMossa];
}
protected synchronized void setTurno(int turnoRicevuto)
{
turno = turnoRicevuto;
}
protected synchronized int getTurno()
{
return turno;
}
//[...]
}
Is there a way to implement a sort of that diagram that i thought?
Thank you all in advance for the help! And sorry for my English, it's not my primary language.
Instead of trying to "accept two connections at a time", you should accept one connection at a time. If there's no waiting connection, the connection should be put to a waiting list. If there is a waiting connection, pair them up.
That way you'll have a single accept() per loop, but 2 possible ways to handle them.
Related
I would like to launch a server who listens simultaneously to two different ports and with a different treatment to incoming connections (I launch a differnet slave depending on port). I did something like this:
public class ServeurMaitre {
public static ServerSocket serverSocket = null;
int poolSize = 15;
private ExecutorService pool = null;
ServeurMaitre(int port, int size){
try {
serverSocket = new ServerSocket(port, size);
pool = Executors.newFixedThreadPool(poolSize);
System.out.println("Serveur en marche. En attente des clients");
} catch (IOException ex) {
Logger.getLogger(ServeurMaitre.class.getName()).log(Level.SEVERE, null, ex);
}
}
void ConnexionServeur() throws IOException {
while(true) {
Socket cnx = serverSocket.accept();
if (cnx.getLocalPort()==3333) {
pool.execute(new EsclaveXML(cnx, this));
}
if(cnx.getLocalPort()==8000) {
pool.execute(new EsclaveHTTP(cnx, this));
}
}
}
public class Main{
public static void main(String[] args) throws IOException {
ServeurMaitre serveur = new ServeurMaitre(8000, 1);
ServeurMaitre serveur1 = new ServeurMaitre(3333, 1);
serveur.Initialisation();
serveur.ConnexionServeur();
serveur1.ConnexionServeur();
}}
Problem: connexions that arrive on port 3333 are well treated but those who are on 8000 don't.
Any help please? Thank you.
I think, cause of the problem is "static serverSocket" variable.
You can change this line
public static ServerSocket serverSocket = null;
to
public ServerSocket serverSocket = null;
I´m trying to do a client that reads data from two servers simultaneously, for example, the client sends a string to both servers that capitalize it and then sends it back to the client.
Client Side
public class Client {
public static void main(String[] args) {
Connection c1 = new Connection("localhost", 2345, "example one");
c1.start();
Connection c2 = new Connection("localhost", 2346, "example two");
c2.start();
Server side
public class Connection implements Runnable {
private String host;
private int port;
private PrintWriter os;
private volatile boolean running = false;
private String stringToCap;
public Connection(String host, int port, String stringToCap) {
this.host = host;
this.port = port;
this.stringToCap = stringToCap;
}
public void start() {
try {
this.os = new PrintWriter(new Socket(host, port).getOutputStream());
} catch (IOException e) {
return;
}
running = true;
new Thread(this).start();
#Override
public void run() {
while(running) {
stringToCap.toUpperCase();
os.print(stringToCap);
}}
But I cant seem to get the server to print back the now capitalized string to the client. When I try the above I get nothing, Do I need a main method on the server side too?
Seems like you have a misconception.
Your current code is just a multi-thread application with 2 threads called Connection and not a true Client and Server application.
Please refer to the Java Tutorial, Custom Networking section.
I am creating a Chat client that is making about 500,000 user registrations by communicating with a server. The client sends a request to the server, then it sends a response back to the client after processing the request. I have implemented this using an Iterative Server and a MultiThreaded server which uses a the ExecutorService framework in Java. I have a fixed thread pool of size 10. I am now trying to measure the average number of registration responses I get back from the Server per second for the Iterative and Multi-Threaded case. I observed that I got fewer responses from the Multi-Threaded as compared to the Iterative. This does not make sense, as I have 10 threads which can simultaneously process requests on the Multi-Threaded server. I'm not sure if I am programming it wrong or if I am misunderstanding a concept here. I would appreciate some help.
EDIT: I tried replacing pool.execute(new SpawnConnection(client)); with Thread thread = new Thread(new SpawnConnection(client)); thread.start(); and the number of responses per second decreased even further.
public class MultiThreadedServer {
public static final int THREAD_COUNT = 10;
private static ExecutorService pool = Executors.newFixedThreadPool(THREAD_COUNT);
private static HashMap<String,Chat> chatGroup = new HashMap<String,Chat>();
private static HashMap<String,Long> heartbeatChecker = new HashMap<String,Long>();
public static synchronized void putHeartbeat(String user){
heartbeatChecker.put(user, System.currentTimeMillis());
}
public static synchronized void putGroup(String user, Chat c){
chatGroup.put(user,c);
}
public static void main(String [] args){
ServerSocket server = null;
Socket client;
int port = Integer.parseInt(args[0]);
try{
server = new ServerSocket(port);
}catch (IOException e1){
e1.printStackTrace();
System.exit(1);
}
while(true){
try {
client = server.accept();
pool.execute(new SpawnConnection(client));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Here is the SpawnConnectionClass:
public class SpawnConnection implements Runnable{
private Socket client;
public SpawnConnection(Socket client){
this.client = client;
}
#Override
public void run() {
// TODO Auto-generated method stub
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter writer = new PrintWriter(client.getOutputStream(),true);
String line = reader.readLine();
if(line.startsWith("register ")){
if(register(line)){
writer.println("Registration Success");
}
else{
writer.println("Error on Registration");
}
}
else{
writer.println("Invalid request");
}
client.close();
}catch(IOException e){
}
}
private boolean register(String line){
String params[] = line.split(" ");
if(MultiThreadedServer.groupContains(params[1])){
return false;//writer.println("Error on register: username already exists. please try again.");
}
else{
try {
MultiThreadedServer.putGroup(params[1], new Chat(params[2],Integer.parseInt(params[3])));
MultiThreadedServer.putHeartbeat(params[1]);
}catch(Exception e){
return false;
}
return true;
}
}
}
I wanted to create a simple game with a server and more than one clients. Server will have several Hashmaps and Arraylists. Server will broadcast these to clients, then one by one a client may modify these and send back to server and then server will broadcast updated values to all clients.
To get started, I have created Server - Client chat app. When a client sends String message to server, Server will add that String message to it's Arraylist and will broadcast that arraylist to all clients. I have used threads so that multiple clients can send messages concurrently, but I haven't applied thread-safety yet.
Lets come to the problem. for the first time when a client sends String to server, server prints it well, add to it's arraylist, then broadcasts it to all clients and all clients can see that too. But next time when client sends String message, server accepts it, adds to arraylist and broadcasts it, but this time all clients gets old arraylist ( list with only one String which was added first ). I have printed arraylist before broadcasting and it shows modified values, but at client side it shows list with one entry only.
Part of Server code
public class ServerGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
private ServerSocket ss;
ArrayList<String> al;
ArrayList<ClientHandler> clients;
public ServerGUI() {
initComponents();
setVisible(true);
al = new ArrayList<>();
clients = new ArrayList<>();
initNet();
}
private void initNet() {
Socket ds = null;
try {
ss = new ServerSocket(SERVER_PORT, 1);
while (true) {
ds = ss.accept();
clients.add(new ClientHandler(ds));
}
} catch (Exception e) {
System.out.println("shutting down server......");
}
}
class ClientHandler extends Thread {
private Socket ds;
private ObjectOutputStream out;
private ObjectInputStream in;
public ClientHandler(Socket ds) throws Exception {
this.ds = ds;
out = new ObjectOutputStream(ds.getOutputStream());
in = new ObjectInputStream(ds.getInputStream());
start();
}
public ObjectOutputStream getOut() {
return out;
}
public void run() {
try {
while (true) {
acceptData(in);
broadcastData();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Finally called. socket closed");
if (ds != null) {
try {
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private void acceptData(ObjectInputStream in) throws Exception {
System.out.println("acceptData called by " + Thread.currentThread().getName());
String s = (String) in.readObject();
al.add(s);
jta.setText(al.toString());
}
private void broadcastData() throws Exception {
System.out.println("broadcast called by " + Thread.currentThread().getName());
System.out.println("al is : \n" + al);
for (ClientHandler clnt : clients) {
clnt.getOut().writeObject(al);
clnt.getOut().flush();
}
}
Part of Client code
public class ClientGUI extends javax.swing.JFrame {
public static final int SERVER_PORT = 4000;
public static final String SERVER_IP = "127.0.0.1";
private Socket s1;
private ObjectOutputStream out;
private ObjectInputStream in;
private ArrayList<String> al;
public ClientGUI() {
initComponents();
setVisible(true);
initNet();
}
private void initNet() {
try {
s1 = new Socket(SERVER_IP, SERVER_PORT);
out = new ObjectOutputStream(s1.getOutputStream());
in = new ObjectInputStream(s1.getInputStream());
System.out.println("connected to server");
new ReadData();
} catch (Exception e) {
e.printStackTrace();
}
}
class ReadData extends Thread {
public ReadData() {
start();
}
public void run() {
System.out.println("client thread started");
try {
while (true) {
al = (ArrayList<String>) in.readObject();
System.out.println("client read completed, al is "+al);
jta.setText(al.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void textFieldActionPerformed(java.awt.event.ActionEvent evt) {
try {
out.writeObject(jtf.getText());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
This is normal behavior. If you send the same object (your ArrayList) several times to a given ObjectOutputStream, the stream will send the full object the first time, and will only send a reference to this object the next times. This is what allows sending a graph of objects without consuming too much bandwidth, and without going into infinite loops because a references b which also references a.
To make sure the ArrayList is sent a second time, you need to call reset() on the ObjectOutputStream.
i have coded a socket listener that should listen on port 80 and 81 and when data arrive on these ports execute operations on these data. I want this listener to concurrently listen on both these ports and hav coded in the following way.
import java.net.*;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class MultipleSocketServer implements Runnable {
private int a;
private ServerSocket connection;
private String TimeStamp;
private int ID;
public static void main(String[] args){
// System.out.print("ip");
// String gh="12345";
//System.out.println(gh.substring(1,3));
int port = 80;
int port1 = 81;
int count = 0;
double a=234.52121;
//System.out.println(bf3.toString());
try{
ServerSocket socket1 = new ServerSocket(port);
ServerSocket socket2=new ServerSocket(port1);
System.out.println("MultipleSocketServer Initialized");
Runnable runnable = new MultipleSocketServer(socket1, ++count);
Runnable run = new MultipleSocketServer(socket2, ++count);
Thread thread = new Thread(runnable);
Thread thread1 = new Thread(run);
while (true) {
//Socket connection = socket1.accept();
thread.start();
thread1.start();
}
}
catch (Exception e) {}
}
MultipleSocketServer(ServerSocket s, int i) {
this.connection = s;
this.ID = i;
}
public void run() {
while(true){
try {
Socket incoming=connection.accept();
BufferedInputStream is = new BufferedInputStream(incoming.getInputStream());
int character;
while((character = is.read())!=-1) {
.
.
do the input data handling here
.
.
}
}
catch(Exception e){}
}
}
}
But for some reason this does not seem to show the threaded/conncurrent behaviour.
I am testing this code using Hyperterminal, and every time i disconnect from hyperterminal, the program execution stops and "Socket is closed" exception is raised.
Any pointers would be of great help
Cheers
You're starting threads in an endless loop.
while (true) {
//Socket connection = socket1.accept();
thread.start();
thread1.start();
}
I think though, that this is handled (ignored) in
} catch (Exception e) {}
However, I suspect that the problem you describe is in in the handling code you didn't include. One pretty obvious idea: you don't call connection.close() instead of incoming.close(), do you?