Second thread quits instead of looping forward - java

This program uses a client to send a Computer object (attributes brand, price, quantity) and the server returns the total charge back to the client. It must be able to continuously run a loop that sends forward threads to a server.
However, after the second thread should be completed, the program stops. I need to figure out how to keep it running, Thank you. Classes attached are Computer, ComputerServer w/ HandleAClient, and ComputerClient. I apologize for the editing, i am still learning how to use this.
import java.io.Serializable;
public class Computer implements Serializable
{
private String brand;
private double price;
private int quantity;
public Computer()
{
setBrand("");
setPrice(0.0);
setQuantity(0);
}
public Computer(String b, double p, int q)
{
setBrand(b);
setPrice(p);
setQuantity(q);
}
public String getBrand()
{
return brand;
}
public double getPrice()
{
return price;
}
public int getQuantity()
{
return quantity;
}
public void setBrand(String b)
{
brand = b;
}
public void setPrice(double p)
{
price = p;
}
public void setQuantity(int q)
{
quantity = q;
}
public String toString()
{
return("Brand: "+brand+"\t"+"Price: "+price+"\t"+"Quantity: "+quantity);
}
}
import java.util.*;
import java.io.*;
import java.net.*;
public class ComputerClient
{
public static void main(String args[])
{
Socket connection;
Scanner scanner = new Scanner(System.in);
Scanner quantity = new Scanner(System.in);
Scanner price = new Scanner(System.in);
Scanner brand = new Scanner(System.in);
ObjectOutputStream output;
ObjectInputStream input;
String b;
double p;
int q;
Object obj;
try
{
int exit= 1;
connection = new Socket("localhost",8000);
output = new ObjectOutputStream(connection.getOutputStream());
input = new ObjectInputStream(connection.getInputStream());
while(exit!=-1)
{
System.out.println("Please Enter a Computer Brand\n");
b = brand.nextLine();
System.out.println("Please Enter the Price\n");
p = price.nextDouble();
System.out.println("Please Enter the Quantity\n");
q = quantity.nextInt();
Computer c = new Computer(b,p,q);
output.writeObject(c);
output.flush();
//read back:
obj=(Object)input.readObject();
System.out.println(obj.toString());
System.out.println("Press any Integer to Continue, To Exit Press -1");
exit = scanner.nextInt();
}
}
catch(ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
import java.io.*;
import java.util.*;
import java.net.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class ComputerServer
{
public static void main(String args[])
{
ServerSocket serverSocket;
Socket connection;
ObjectInputStream input;
ObjectOutputStream output;
Computer c = null;
Object obj;
double totalCharge;
try
{
serverSocket = new ServerSocket(8000);
System.out.println("Waiting for Client");
int clientNo = 1;
ExecutorService threadExecutor = Executors.newCachedThreadPool();
while(true)//runs indefinitely
{
connection = serverSocket.accept();
input = new ObjectInputStream(connection.getInputStream());
output = new ObjectOutputStream(connection.getOutputStream());
obj = input.readObject();
System.out.println("\nObject Received from Client:\n"+obj);
if(obj instanceof Computer)
{
totalCharge = ((Computer)obj).getPrice()*((Computer)obj).getQuantity();
HandleAClient thread = new HandleAClient(connection, clientNo, totalCharge);
threadExecutor.execute(thread);
output.writeObject(totalCharge);
output.flush();
}
clientNo++;
}
}
catch(ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}//end of main
}
class HandleAClient implements Runnable
{
//**SHOULD i do object...
//Scanner input;
//Formatter output;
Object obj;
ObjectOutputStream output;
ObjectInputStream input;
Socket connection;
ServerSocket serverSocket;
int clientNo;
//variables for calculation
//variables for calculation
double price;
double totalCharge;
public HandleAClient(Socket connection, int clientNo, double totalCharge)
{
this.connection = connection;
this.clientNo = clientNo;
this.totalCharge = totalCharge;
}
public void run()
{
//ArrayList<Computer> cList = new ArrayList<Computer>();
//connection = serverSocket.accept();
/*while(input.hasNext())
{
//variable = input.next....
//print out calculation
price = input.nextDouble();
System.out.println("Price received from client:\t"+clientNo+"is"+price);
//DO CALCULATION, STORE IT
for(Computer c: cList)//**TRYING a for loop
{
totalCharge = ((Computer)c).getPrice() * ((Computer)c).getQuantity();
output.format("%.2f\n", totalCharge);
//output.flush();
}
//}*/
System.out.println("\nTotal Charge\t"+totalCharge);
System.out.println("\nThread"+"\t"+clientNo+"\t"+"ended");
}
}

You messed up in a Server:
You are receiving object in a main thread, than you make a new thread that does nothing. So you receive information from the socket only once.
Another connection was obtained without a problem, but the old connection information was lost. The client was writing to its socket but you didn't do anything with it, because you've lost a reference to the stream.
I suppose you thought that new object comes to the server as a new socket, which was wrong.
try using this code for a Server:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class ComputerServer
{
public static void main(String args[]) throws IOException
{
ServerSocket serverSocket;
Socket connection;
serverSocket = new ServerSocket(8000);
int clientNo = 1;
ExecutorService threadExecutor = Executors.newCachedThreadPool();
while (true)// runs indefinitely
{
System.out.println("Waiting for client");
connection = serverSocket.accept();
System.out.println("Client connected: " + connection.getPort());
HandleAClient thread = new HandleAClient(connection, clientNo);
threadExecutor.execute(thread);
clientNo++;
}
}
}
class HandleAClient implements Runnable
{
ObjectOutputStream output;
ObjectInputStream input;
ServerSocket serverSocket;
int clientNo;
public HandleAClient(Socket connection, int clientNo)
{
this.clientNo = clientNo;
try
{
this.input = new ObjectInputStream(connection.getInputStream());
this.output = new ObjectOutputStream(connection.getOutputStream());
} catch (IOException e)
{
e.printStackTrace();
}
}
#Override
public void run()
{
while (true)
{
try
{
Object obj = input.readObject();
System.out.println("\nObject Received from Client:\n" + obj);
if (obj instanceof Computer)
{
Computer c = (Computer) obj;
double totalCharge = c.price * c.quantity;
System.out.format("\nTotal Charge[%d]\t%f", clientNo,
totalCharge);
output.writeObject(totalCharge);
output.flush();
}
} catch (Exception e) { //JUST FOR BREVITY
e.printStackTrace();
}
}
}
}

Related

Problem in Client and Server Architecture. Exception in thread appears

I wrote this code in java based on sockets and thread pool. The server code runs on its own but when I run the client code after running the server, an exception on the server appears. What could be causing this?
Below is the server class which conatains threads for each new client
package java_40;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//Server Implementation
/**
*
* #author Abdullah
*/
public class Server implements Runnable {
private ArrayList<ConnectionHandler> connections;
private ServerSocket server;
private boolean done;
private ExecutorService pool;
public Server (){
connections = new ArrayList<>();
done = false;
}
#Override
public void run() {
try {
while(!done){
server = new ServerSocket(9999);
pool = Executors.newCachedThreadPool();
Socket client = server.accept();
ConnectionHandler handler = new ConnectionHandler(client);
connections.add(handler);
pool.execute(handler);
}
} catch (IOException ex) {
shutdown();
}
}
public void broadcast(String message){
for(ConnectionHandler ch :connections){
if(ch !=null){
ch.sendMessage(message);
}
}
}
public void shutdown(){
try{
done=true;
if(!server.isClosed()){
server.close();
}
for(ConnectionHandler ch : connections){
ch.shutdown();
}
}catch(IOException e){
// ignore
}
}
class ConnectionHandler implements Runnable{ //handles individual client connection
private final Socket client;
private BufferedReader in;
private PrintWriter out;
private String nickname;
public ConnectionHandler(Socket client){
this.client = client;
}
#Override
public void run() {
if(client != null){
try{
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out.println("Enter nickname");
nickname =in.readLine();
System.out.println(nickname+" connected");
broadcast(nickname + " has joined the chat");
String message;
while((message = in.readLine()) !=null){
if (message.startsWith("/nick"))
{
// TODO: handle nickname
String[] messageSplit = message.split(" ", 2);
if(messageSplit.length == 2){
broadcast(nickname + " renamed themselves to " + messageSplit[1]);
System.out.println(nickname + " renamed themselves to " + messageSplit[1]);
nickname = messageSplit[1];
out.println("Successfully changed nickname to " + nickname);
}else{
out.println("No nickname provided");
}
}
else if(message.startsWith("/quit")){
broadcast(nickname + " has left the chat");
// shutdown();
}
else{
broadcast(nickname + ": " + message);
}
}
} catch(IOException e){
if(this.in != null && this.out != null){
shutdown();
}
}
}
}
public void sendMessage(String message){
out.println(message);
}
public void shutdown(){
try{
in.close();
out.close();
if(!client.isClosed()){
client.close();
}
}catch(IOException e){
// ignore
}
}
}
public static void main(String[] args) {
// TODO code application logic here
Server server =new Server();
server.run();
}
}
below is the client class in which client has been implemented. A great number of clients can connect to the server through cmd.
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package java_40;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class client implements Runnable{
private Socket client;
private BufferedReader in;
private PrintWriter out;
private boolean done;
#Override
public void run() {
try{
Socket client = new Socket("127.0.0.1",9999); // if you want to connect to someone elses server replace the ip with their ip as of now this our own ip
out = new PrintWriter(client.getOutputStream(),true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
InputHandler inHandler = new InputHandler();
Thread t = new Thread(inHandler);
t.start();
String inMessage;
while((inMessage = in.readLine()) != null )
{
System.out.println(inMessage);
}
}catch(IOException e){
// shutdown();
}
}
private void shutdown(){
done =true;
try{
in.close();
out.close();
if(!client.isClosed()){
client.close();
}
}catch(IOException e){
// ignore
}
}
class InputHandler implements Runnable{
#Override
public void run() {
try{
BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in));
while(!done){
String message = inReader.readLine();
if(message.equals("/quits")){
inReader.close();
shutdown();
}else{
out.println(message);
}
}
}catch(IOException e){
// shutdown();
}
}
}
public static void main(String[] args) {
client c = new client();
c.run();
}
}

How to handle multiple streams from a lobby server to clients

So, I'm having an issue with a project of mine. I'm writing a multiplayer lobby system which will enable multiple users to join a lobby, readying themselves by pressing a key. The issue that I'm facing is when two players is readying themselves, the lobby is only printing out a message for the last player who readied themselves. The system is built up in the following way.
Main Server
package master;
import java.net.*;
import java.io.*;
import java.util.*;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import main.Lobby;
public class MainServer {
public static final int PORT = 4444;
public static final String HOST = "localhost";
public ArrayList<Lobby> serverList = new ArrayList<>();
public static void main(String[] args) throws IOException, ClassNotFoundException {
new MainServer().runServer();
}
public void runServer() throws IOException, ClassNotFoundException {
// Creating the server
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Main Server initiated.");
while (true) {
Socket socket = serverSocket.accept();
try {
// Establishing the connection to the Lobby server and then adding it to its list
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject("Server created successfully.");
Lobby s = (Lobby) objectInputStream.readObject();
this.serverList.add(s);
System.out.println("Server \"" + s.name + "\" added to game list.");
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
The lobby
package main;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.Semaphore;
import master.MainServer;
/**
* The Class Server.
*/
public class Lobby implements Serializable {
private static final long serialVersionUID = -21654L;
public static final int PORT = 4445;
public static final int MAX_USERS = 5000;
public static final String HOST = "localhost";
public String name = "Lobby Server";
public int clientNumber;
public int playerNumberReady = 0;
public boolean allPlayersReady = false;
public boolean OddurIsNice = false;
public static void main(String[] args) throws IOException, ClassNotFoundException {
Lobby s = new Lobby();
s.runServer();
}
public void runServer() throws IOException, ClassNotFoundException {
registerServer();
new Thread( () -> {
try {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server waiting for connections...");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("User 1 is now connected");
clientNumber++;
new ObjectOutputStream(socket.getOutputStream()).writeObject("You are connected man");
Socket socket2 = serverSocket.accept();
System.out.println("User 2 is now connected");
clientNumber++;
// ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket2.getOutputStream());
// objectOutputStream2.writeObject("You are player number " + clientNumber + ". Waiting for other players to join");
new ServerThread(socket, socket2).start();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}).start();
}
private void registerServer() throws UnknownHostException, IOException, ClassNotFoundException {
// Method for establishing a connection to the MainServer
Socket socket = new Socket(MainServer.HOST, MainServer.PORT);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream.writeObject(this);
System.out.println((String) objectInputStream.readObject());
}
public class ServerThread extends Thread {
public Socket socket = null;
public Socket socket2 = null;
ServerThread(Socket socket, Socket socket2) {
this.socket = socket;
this.socket2 = socket2;
}
public void run() {
try {
// This method is for when the client want's to connect to the lobby
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
System.out.println("User 1 is now connected");
ObjectInputStream objectInputStream2 = new ObjectInputStream(socket2.getInputStream());
ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket2.getOutputStream());
System.out.println("User 2 is now connected");
BoardGameClient joined = (BoardGameClient) objectInputStream.readObject();
System.out.println(joined.name + " is now connected.");
while(true) {
objectOutputStream.writeObject("You joined the server.");
objectOutputStream.writeObject("You are player Number " + 1);
objectOutputStream.writeObject("Press '1' if you are ready");
objectOutputStream2.writeObject("You joined the server.");
objectOutputStream2.writeObject("You are player Number " + 2);
objectOutputStream2.writeObject("Press '1' if you are ready");
if(objectInputStream.readObject().equals(1)) {
playerNumberReady++;
}
if(objectInputStream2.readObject().equals(1)) {
playerNumberReady++;
}
if(playerNumberReady != 2) {
allPlayersReady = false;
} else {
allPlayersReady = true;
}
if (allPlayersReady == false) {
objectOutputStream.writeObject("Waiting...");
objectOutputStream2.writeObject("Waiting...");
}
if (allPlayersReady == true) {
objectOutputStream.writeObject("Lets GO");
objectOutputStream2.writeObject("Lets GO");
}
while (true) {
System.out.println(objectInputStream.readObject());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And the client
package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.concurrent.Semaphore;
import master.MainServer;
public class BoardGameClient implements Serializable {
private int playerName;
private static final long serialVersionUID = -6224L;
public String name = "User";
private transient Socket socket;
public transient Scanner input = new Scanner(System.in);
public static void main(String[] args) {
BoardGameClient c = new BoardGameClient();
if (args.length > 0) {
c.name = args[0];
}
try {
c.joinServer();
} catch (ClassNotFoundException | IOException e) {
System.out.println("Failed to join server.");
e.printStackTrace();
}
}
public void joinServer() throws UnknownHostException, IOException, ClassNotFoundException {
socket = new Socket(Lobby.HOST, Lobby.PORT);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
while(true) {
objectOutputStream.writeObject(this);
BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
System.out.println(objectInputStream.readObject());
int ready = input.nextInt();
objectOutputStream.writeObject(ready);
System.out.println(objectInputStream.readObject());
objectOutputStream.writeObject(name + ": " + inputReader.readLine());
}
}
}
I sincerely hope, that someone will be able to help me out <3
Firstly, there's a few things that bug me about this code. Not to sound condescending but you need to avoid rewriting code as much as possible. What happens if you want 3 or more players in the future? Currently you'd have to manually create a whole socket eg socket3, and then rewrite all the code you've already written. This is bad. You've manually spent the time creating 2 sockets and then created 2 streams for both of these sockets etc etc.
This can be automated don't you think?
Secondly, you have a lot of public variables. Unless they are static and final, for the most part you should keep variables as private.
I've tinkered with your lobby class as seen below, which is more scalable. It's not perfect by any means, but I feel illustrates the direction of improvement you should be heading for. Look up SOLID OOP principles, they'll help you guaranteed.
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* The Class Server.
*/
public class Lobby implements Serializable {
private static final long serialVersionUID = -21654L;
public static final int PORT = 4445;
public static final int MAX_USERS = 5000;
public static final String HOST = "localhost";
private static final int MIN_USERS = 2;
private String name = "Lobby Server";
private int clientNumber;
private boolean gameRunning = false;
// set of client connections
private final Set<ServerThread> clientConnectionThreads = new LinkedHashSet<>();
public static void main(String[] args) throws IOException, ClassNotFoundException {
Lobby s = new Lobby();
s.createLobby();
}
public void createLobby() throws IOException, ClassNotFoundException {
// waits for all players to ready up in a different thread
new Thread(this::waitReady).start();
registerServer();
// Listens for clients
runServer();
}
public void runServer() {
// closes serverSocket automatically in this way
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server waiting for connections...");
long ids = 0;
while (!gameRunning) {
// accepts a new client connection
Socket socket = serverSocket.accept();
if (clientConnectionThreads.size() >= MAX_USERS) {
// tell user server is full and dont add the connection
} else {
// calculates the new id of the incoming player and adds them to the lobby
ids++;
this.clientConnectionThreads.add(new ServerThread(ids, socket));
System.out.println("User " + ids + " is now connected");
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
/*
* loops until every player is ready and there is enough players and then starts
* the game.
*/
public void waitReady() {
while (true) {
try {
if (areAllReady() && this.clientConnectionThreads.size() >= MIN_USERS) {
startGame();
return;
}
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// returns true if all users are ready
public boolean areAllReady() {
return clientConnectionThreads.stream().allMatch(ServerThread::isReady);
}
public void startGame() {
System.out.println("Starting game...");
this.gameRunning = true;
clientConnectionThreads.forEach(ServerThread::startGame);
// do game stuff
}
// i havent touched this function
private void registerServer() throws UnknownHostException, IOException, ClassNotFoundException {
// Method for establishing a connection to the MainServer
Socket socket = new Socket(MainServer.HOST, MainServer.PORT);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
objectOutputStream.writeObject(this);
System.out.println((String) objectInputStream.readObject());
}
public class ServerThread extends Thread {
private final Socket socket;
private final ObjectInputStream in;
private final ObjectOutputStream out;
private final long id;
boolean ready = false;
private ServerThread(long id, Socket socket) throws IOException {
// does some basic initialization
this.socket = socket;
this.id = id;
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
// starts this connection thread
this.start();
}
public boolean isReady() {
return ready;
}
public void run() {
try {
// sets up the client and waits for their input
BoardGameClient joined = (BoardGameClient) in.readObject();
System.out.println(joined.name + " is now connected.");
out.writeObject("You joined the server.");
out.writeObject("You are player Number " + id);
out.writeObject("Press '1' if you are ready");
out.flush();
// waits for user to return ready
while (!ready) {
try {
int input = in.readInt();
System.out.println("input: " + input);
ready = input == 1;
} catch (ClassCastException e) {
e.printStackTrace();
}
}
out.writeObject("Waiting for players...");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startGame() {
// send client message etc etc
}
}
public String getName() {
return name;
}
}
I basically didn't change any of the other classes, except a few lines within the client class to make this work. (I've changed the ready input type from writeObject() to writeInt())
I haven't tested this for problems, but I know it works at least on a basic level.
I also suggest using writeUTS()/readUTS() instead of writeObject()/readObject() for sending and receiving Strings across streams as this will add extra complexity to the code.

send a message to specific client threads

I have this Server class,
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public static ArrayList<String> waiting = new ArrayList<String>();
public static ArrayList<String> playing = new ArrayList<String>();
public static ArrayList<Integer> score = new ArrayList<Integer>();
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(4321);
while (true) {
try {
Socket socket = server.accept();
new EchoThread(socket).start();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void addClient(String name) {
waiting.add(name);
}
public int getNumClients() {
return waiting.size();
}
public String getClientName(int i) {
return waiting.get(i);
}
public void play() {
int scr = 0;
for (int i = 0; i < 4; i++) {
playing.add(waiting.get(0));
score.add(scr);
waiting.remove(0);
}
}
public boolean checkIfPlaying(String name) {
if (playing.indexOf(name) >= 0) {
return true;
} else {
return false;
}
}
}
and the Thread Class,
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoThread extends Thread {
protected Socket socket;
public EchoThread(Socket clientSocket) {
this.socket = clientSocket;
}
public void run() {
Server s = new Server();
DataInputStream in = null;
DataOutputStream out = null;
String line;
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
while (true) {
try {
line = in.readLine();
String[] prot = line.split(":");
if (prot[0].equals("/login")) {
s.addClient(prot[1]);
} else if (prot[0].equals("/waiting")) {
if (s.checkIfPlaying(prot[1])) {
out.writeBytes("Playing" + "\r\n");
} else {
if (s.getNumClients() >= 4) {
s.play();
out.writeBytes("Playing" + "\r\n");
} else {
out.writeBytes(s.getNumClients() + "\r\n");
}
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
If the client connect to the server, the name of the client is stored in Server Class Array, waiting.
If the waiting clients is equals to 4, it will remove from the waiting array and put it in playing array.
I would like to make the server send message to the first 4 clients in playing array.
How can I do it?
For your Server Class, I would change your ArrayList< String > for waiting and playing to ArrayList< EchoThread >. This way your Server class is tracking each client object themselves instead of just their names. When you instantiate your EchoThread objects, I would pass the local server object to each EchoThread that way each object knows about the server that instantiated them.
Server Class
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
public ArrayList<EchoThread> waiting = new ArrayList<EchoThread>();
public ArrayList<EchoThread> playing = new ArrayList<EchoThread>();
public ArrayList<Integer> score = new ArrayList<Integer>();
public static void main(String[] args) {
try {
// Instantiate a single server object that you can pass into your connected clients
Server myServer = new Server();
ServerSocket server = new ServerSocket(4321);
while (true) {
try {
Socket socket = server.accept();
// Pass myServer into Echo Thread
new EchoThread(myServer, socket).start();
} catch (Exception exc) {
exc.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Have to synchronize this since multiple clients could be adding to this list at the same time
public synchronized void addClient(EchoThread client) {
waiting.add(client);
}
public int getNumClients() {
return waiting.size();
}
public String getClientName(int i) {
return waiting.get(i).getCName();
}
public void play() {
int scr = 0;
for (int i = 0; i < 4; i++) {
EchoThread clientBeingMovedToPlaying = waiting.get(0);
playing.add(clientBeingMovedToPlaying);
score.add(scr);
waiting.remove(0);
// This will be a new method in your EchoThread class
clientBeingMovedToPlaying.SendServerPlayingMessage();
}
}
public boolean checkIfPlaying(String name) {
boolean isPlaying = false;
for(EchoThread client : playing) {
if (client.getName().contentEquals(name)) {
isPlaying = true;
break;
}
}
return isPlaying;
}
}
For your Echo Thread class, I would make your variables in your run method class variables so they can be used throughout the class
EchoThread Class
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class EchoThread extends Thread {
protected Socket socket;
protected Server s;
protected DataInputStream in;
protected DataOutputStream out;
protected String line;
protected String clientName;
// This way, each EchoThread object knows about the server
public EchoThread(Server theServer, Socket clientSocket) {
this.s = theServer;
this.socket = clientSocket;
}
public void run() {
try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
return;
}
while (true) {
try {
line = in.readLine();
String[] prot = line.split(":");
if (prot[0].equals("/login")) {
// Original code
//s.addClient(prot[1]);
// New code
clientName = prot[1];
s.addClient(this);
} else if (prot[0].equals("/waiting")) {
if (s.checkIfPlaying(prot[1])) {
out.writeBytes("Playing" + "\r\n");
} else {
// You don't want multiple clients firing the play method, so you need to synchronize your server object
synchronized (s) {
if (s.getNumClients() >= 4) {
s.play();
out.writeBytes("Playing" + "\r\n");
} else {
out.writeBytes(s.getNumClients() + "\r\n");
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
public String getCName() {
return clientName;
}
public void SendServerPlayingMessage() {
if (out != null) {
// Send whatever message you want
}
}
}
I think this'll get you what your wanting... Forgive any syntax or logical errors, I don't have an IDE right in front of me at the moment.

Multi-threading client/server, Socket Exception

Should be a simple fix that i am not able to correct. I am returning a total calculation, price * quantity, between the server and the client. However, I am receiving a java.net.SocketException: Connection Reset. I have inserted a ComputerServer class w/class HandleAClient, ComputerClient class and Computer class. I welcome any help. Thank you!
import java.io.*;
import java.util.*;
import java.net.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class ComputerServer
{
public static void main(String args[])
{
ServerSocket serverSocket;
Socket connection;
ObjectInputStream input;
ObjectOutputStream output;
Computer c = null;
Object obj;
double totalCharge;
try
{
serverSocket = new ServerSocket(8000);
System.out.println("Waiting for Client");
int clientNo = 1;
ExecutorService threadExecutor = Executors.newCachedThreadPool();
while(true)//runs indefinitely
{
connection = serverSocket.accept();
input = new ObjectInputStream(connection.getInputStream());
output = new ObjectOutputStream(connection.getOutputStream());
obj = input.readObject();
System.out.println("Object Received from client:\n"+obj);
if(obj instanceof Computer)
{
totalCharge = ((Computer)obj).getPrice()*((Computer)obj).getQuantity();
HandleAClient thread = new HandleAClient(connection, clientNo, totalCharge);
threadExecutor.execute(thread);
output.writeObject(totalCharge);
output.flush();
}
clientNo++;
}
}
catch(ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}//end of main
}
class HandleAClient implements Runnable
{
//**SHOULD i do object...
//Scanner input;
//Formatter output;
Object obj;
ObjectOutputStream output;
ObjectInputStream input;
Socket connection;
ServerSocket serverSocket;
int clientNo;
//variables for calculation
//variables for calculation
double price;
double totalCharge;
public HandleAClient(Socket connection, int clientNo, double totalCharge)
{
this.connection = connection;
this.clientNo = clientNo;
this.totalCharge = totalCharge;
}
public void run()
{
//ArrayList<Computer> cList = new ArrayList<Computer>();
try
{
input = new ObjectInputStream(connection.getInputStream());
output = new ObjectOutputStream(connection.getOutputStream());
/*while(input.hasNext())
{
//variable = input.next....
//print out calculation
price = input.nextDouble();
System.out.println("Price received from client:\t"+clientNo+"is"+price);
//DO CALCULATION, STORE IT
for(Computer c: cList)//**TRYING a for loop
{
totalCharge = ((Computer)c).getPrice() * ((Computer)c).getQuantity();
output.format("%.2f\n", totalCharge);
//output.flush();
}
//}*/
System.out.println("TotalCharge"+totalCharge);
System.out.println("Thread"+"\t"+clientNo+"\t"+"ended");
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
import java.util.*;
import java.io.*;
import java.net.*;
public class ComputerClient
{
public static void main(String args[])
{
Socket connection;
ObjectOutputStream output;
ObjectInputStream input;
Object obj;
Computer c = new Computer("Asus",1189.99,4);
try
{
connection = new Socket("localhost",8000);
output = new ObjectOutputStream(connection.getOutputStream());
input = new ObjectInputStream(connection.getInputStream());
output.writeObject(c);
output.flush();
//read back:
obj=(Object)input.readObject();
System.out.println(obj.toString());
}
catch(ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
import java.io.Serializable;
public class Computer implements Serializable
{
private String brand;
private double price;
private int quantity;
public Computer()
{
setBrand("");
setPrice(0.0);
setQuantity(0);
}
public Computer(String b, double p, int q)
{
setBrand(b);
setPrice(p);
setQuantity(q);
}
public String getBrand()
{
return brand;
}
public double getPrice()
{
return price;
}
public int getQuantity()
{
return quantity;
}
public void setBrand(String b)
{
brand = b;
}
public void setPrice(double p)
{
price = p;
}
public void setQuantity(int q)
{
quantity = q;
}
public String toString()
{
return("Brand: "+brand+"\t"+"Price: "+price+"\t"+"Quantity: "+quantity);
}
}
'Connection reset' usually means you have written to a connection that had already been closed by the peer. In other words, an application protocol error. You've written something that the peer didn't read. The next I/O operation, or a subsequent one depending on buffering, will get 'connection reset'.
In this case the server is writing totalCharge and initializing two ObjectOutputStreams, which both write headers to the stream. The client is only creating one ObjectInputStream, which reads one header, and reads one object, then closes the connection. So the other header is written nowhere and causes the exception.
You can't do this. You can't use multiple ObjectOutputStreams on the same socket, at least not without special care that isn't evident here. You also shouldn't be doing any I/O whatsoever in the accept loop. Move all the client processing to the HandleAClient class, which is what it's for after all, and don't do anything in the accept loop except accept connections and start threads for them.
Also neither your server nor your client is closing the connection. The server is just leaking sockets, and the client is just exiting. The operating system is closing it for you in the client case, but it's poor practice. Close your connections. In this case you should close the ObjectOutputStream.

chat in java not synchronized (sockets, threads)

I'm trying to figure out a way to get an instance of a server to negotiate between two clients by creating a chat thread between them.
I created this project, and it "almost" works... but it seems like there is a buffer of synch problem.
when writing a line in one side (i.e Client#1), it doesn't pass to the other side (i.e Client#2), but only after Client#2 trys to pass a line too.
I know there might be better ways to implement this, but I'd like to understand what's wrong with my code.
your help would be great!
the code:
server
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String[] args)
{
int id = 1;
System.out.println();
System.out.println("Server");
try
{
ServerSocket serverSocket = new ServerSocket(4321);
while (true)
{
Socket client1Socket = serverSocket.accept();
Socket client2Socket = serverSocket.accept();
System.out.println("clients connected from ports: \n"
+ client1Socket.getPort() + ", " + client2Socket.getPort());
Thread client1Thread = new ServerThread(client1Socket, client2Socket, id);
client1Thread.start();
id++;
Thread client2Thread = new ServerThread(client2Socket, client1Socket, id);
client2Thread.start();
id++;
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
server thread
import java.io.*;
import java.net.*;
import java.util.*;
public class ServerThread extends Thread
{
Socket sourceSocket;
Socket destSocket;
int id;
public ServerThread(Socket src, Socket dst, int n)
{
sourceSocket = src;
destSocket = dst;
id = n;
}
public void run()
{
try
{
Scanner clientInput = new Scanner(sourceSocket.getInputStream());
PrintStream destOutput = new PrintStream(destSocket.getOutputStream());
destOutput.println("You are chatting with Client " + id);
boolean more = true;
while (more)
{
String input = clientInput.nextLine();
destOutput.println(input);
if (input.equals("Q"))
{
more = false;
}
}
sourceSocket.close();
destSocket.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
client
import java.io.*;
import java.net.*;
import java.util.*;
public class Client
{
public static void main(String[] args)
{
System.out.println();
System.out.println("Client");
try
{
Socket clientSocket = new Socket("localhost", 4321);
System.out.println("Connection Established");
Scanner input = new Scanner(clientSocket.getInputStream());
PrintStream output = new PrintStream(clientSocket.getOutputStream());
Scanner in = new Scanner(System.in);
System.out.println(input.nextLine());
boolean more = true;
while (more)
{
String text = in.nextLine();
output.println(text);
String nextInput = input.nextLine();
if (nextInput == null)
{
more = false;
}
else
{
System.out.println(nextInput);
}
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
In your client code, the line String text = in.nextLine(); will block your thread. That means if you never type in anything in your client, you can not receive anything. So the solution is to put your message receiving code in another thread. such as:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (!Thread.interrupted()) {
System.out.println(input.nextLine());
}
}
});
thread.start();
while (true)
{
String text = in.nextLine();
output.println(text);
// String nextInput = input.nextLine();
......................
}

Categories

Resources