Java Server producing inconsistent output - java

I want to integrate a server with multiple clients for a blackjack game I created, and thus I began practicing with servers in java. I create a thread, that when ran, forces the server to listen for input and produce an output. Then I added a feature to stop the server. However, the server randomly produces the correct output, and sometimes fails to connect. Here is the code for when the user hosts a server:
st = new ServerThread(); //this is a field of type ServerThread
st.start(); //this runs the server concurrently as a new thread
Here is the code for when they close a server:
st.stopThread();
Finally, here is the source for the serverThread:
public class ServerThread extends Thread {
private volatile boolean isRunning = true;
private Socket socket;
private static final int PORTNUM = 1342;
#Override
public void run() {
while (isRunning) { //should run only when the
try {
ServerSocket serverSocket = new ServerSocket(PORTNUM); //uses the same port number, which I made a constant
//Reading the an object of type Information from the client
socket = serverSocket.accept();
ObjectInputStream serverInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream serverOutputStream = new ObjectOutputStream(socket.getOutputStream());
Information i = (Information) serverInputStream.readObject();
//arbitrarily changes the data stored in the information object to verify connection with server
i.setI(100);
i.setS("new string");
i.setD(4.4);
//sends the modified object back to the client
serverOutputStream.writeObject(i);
serverInputStream.close();
serverOutputStream.close();
socket.close();
} catch (IOException e) {
//System.out.println("IOException");
//e.printStackTrace();
} catch (ClassNotFoundException e) {
//System.out.println("ClassNotFoundException");
//e.printStackTrace();
} finally {
try {
if (socket != null) { //avoid null pointer if no connections have been established
socket.close();
}
} catch (IOException ex) {
//Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public void stopThread() {
isRunning = false;
}
}
Any suggestions on edits to make my code perform correctly and consistently would be welcome. Thanks.

I would move the socket definition away from being an instance variable i.e,
while (isRunning) {
Socket socket = null;
try {
...

Related

How can I break a while loop with ServerSocket.accept() inside without throwing exception?

I connect multiple clients to a server using Sockets and a ServerSocket. Currently my servers run() method has a while(bool) loop that creates a new socket whenever a client tries to connect but I want to break the loop from another method. Sounds easy but simply changing the boolean to false won't do since something waits on serverSocket.accept() for it to, well, accept.
Using setSoTimeout didn't work for me, as it throws an exception. I need the thread to loop and wait for new clients until one of them sends a "CLOSE" String via Stream, not for a set period of time, but I could be doing something wrong. I would like to keep serverSocket in try-with-resources so that everything closes when I close the JFrame with mouseclick, still I need it to close from code too. I also tried creating a "Ghost" client that should break the cycle but I think it's not an elegant solution and now I get socket closed exception in ClientThread first line ine while loop. I am so lost please help me.
the code:
class ClientThread implements Runnable{
private Socket socket;
private String name;
private boolean running;
private PhoneBookServer server;
private ObjectOutputStream outputStream = null;
ClientThread(PhoneBookServer server, Socket socket){
this.server = server;
this.socket = socket;
new Thread(this).start();
}
public String getName(){
return name;
}
public void disconnect(){
try {
outputStream.writeObject("OK BYE");
server.printMessage("OK BYE");
running = false;
socket.close();
socket = null;
}catch (IOException e){
e.printStackTrace();
}
}
public void run(){
String message;
try(ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());){
outputStream = output;
name = (String) input.readObject();
running = true;
server.addClient(this);
while(running){
message = (String) input.readObject();
server.printMessage(this, message);
if(message.equals("BYE")){
disconnect();
server.removeClient(this);
}
if(message.equals("CLOSE")){
server.disconnectAll();
}
}
}catch (Exception e){
e.printStackTrace();
}
}
interesting methods from the Server class:
synchronized void disconnectAll(){
for(ClientThread c : connectedClients){
c.disconnect();
}
running = false;
}
public void run(){
boolean socket_created = false;
try(ServerSocket serverSocket = new ServerSocket(SERVER_PORT)){
String host = InetAddress.getLocalHost().getHostName();
System.out.println("Serwer został uruchomiony na hoście " + host);
socket_created = true;
while(running){
Socket socket = serverSocket.accept();
if (socket != null){
new ClientThread(this, socket);
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}

Android Studio Connect to Socket server

I have a server running in Java using Eclipse (Here the full code):
public class Main {
public static void main(String[]args) {
// BBDD connection var
Connection con = null;
// Sockets
ServerSocket server = null;
try {
server = new ServerSocket(5010);
} catch (IOException e2) {System.out.println("Error at creating server, check if the port is in use");System.exit(-1);}
/*** MySQL driver loading***/
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("MySQL driver is UP");
} catch (ClassNotFoundException e1) {System.out.println("Error loading MySQL driver");}
/*** Stablishing connection with the ddbb ***/
try {
con= (Connection) DriverManager.getConnection("jdbc:mysql://IP/Database", "username", "password");
System.out.println("Connection stablished");
} catch (SQLException e) {
System.out.println("SQL ERROR");
e.printStackTrace();
}
/*** Assigning thread for client ***/
System.out.println("Listening for new requests...");
while (true) {
try {
Socket clientSocket;
clientSocket = server.accept();
System.out.println("Connection stablished");
DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
DataOutputStream dos = new DataOutputStream(clientSocket.getOutputStream());
ThreadForClient client = new ThreadForClient(con, clientSocket, dis, dos);
Thread thread = new Thread(cliente);
thread .start();
} catch (IOException e) {System.out.println("Error making client socket");}
}
}
class ThreadForClient implements Runnable {
Connection con;
Socket clientSocket;
DataInputStream dis;
DataOutputStream dos;
public ThreadForClient(Connection con, Socket s, DataInputStream dis, DataOutputStream dos) {
this.con = con;
this.clientSocket = s;
this.dis = dis;
this.dos = dos;
}
#Override
public void run() {
try {
int opc = dis.readInt();
switch (opc) {
case 1:
String email = dis.readUTF();
Boolean result = existeUsuario(email);
dos.writeBoolean(result);
break;
default: break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Boolean userExists(String email) throws SQLException { // 1
email = email.toLowerCase();
Statement stmt;
stmt = con.createStatement();
ResultSet rs=stmt.executeQuery("select * from users where email = '"+email+"'");
boolean result = rs.first();
return result;
}
}
As you can see, the client sends 2 values and receives 1, the first one is for the switch, which will indicate what to exceute, for now I just have on option (checking if email exists in the ddbb), the second value is the email as the code has already entered the switch.
The server is fully working and I already tested it with a Client Test project in Eclipse (It is what I want to do in Android Studio):
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket(HOST, PORT);
System.out.println("Conection succesful");
DataOutputStream dos;
DataInputStream dis;
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
dos.writeInt(1);
dos.writeUTF("email#example.com");
Boolean bool = dis.readBoolean();
if (bool) {
System.out.println("Email exists in the BBDD.");
} else {
System.out.println("Email does not exist in the BBDD.");
}
socket.close();
} catch (Exception e) {System.out.println("Server connection failed");}
}
Now what I want to do is doing the same client in Android Studio so it can connect to the server.
I tried this:
public class SocketConnection {
UserExists ue;
public SocketConnection() throws IOException {
connect();
}
public void connect() {
ue = new UserExists();
ue.execute();
}
}
class UserExists extends AsyncTask<Void, Void, Void> {
int PORT = 5010;
String HOST = "192.168.1.5";
private Socket socket;
private DataOutputStream dos;
private DataInputStream dis;
#Override
protected Void doInBackground(Void... voids) {
try {
socket = new Socket(HOST, PORT);
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
} catch (Exception e) {
System.out.println("Socket error");
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
When I run it it does not give me any error but if I log the socket value at doInBackground's bottom to see the socket value, it says it is null.
I also tried using Thread and Handle but I can't get the result the server gives me back to the main thread.
According to RFC 1918, addresses in the 192.168.0.0-192.168.255.255 range are private. Such addresses can be used internally by any network so they're often used inside an organization. They cannot be used on the Internet since they aren't unique. Why my ip address starts with 192.?
I think that your local network is somehow preventing that connection. But without further details nobody can actually tell as far I know.
If you are running everything on the same computer you may want to take a look at "loopback" address. Usually 127.0.0.1 , that should loop back to your machine.
If you want to run a full server you may need to dig more into networking and want to understand how networks function.
I managed to resolve this. I just made a thread inside a "Connection" class in Android Studio.
Inside "Connection" I have some class-level variables, which I use with the thread (The thread can't modify variables in the method the thread was created but it can read class-level variables) so the thread itself makes the connection with the socket server and saves the value taken to also a class-level variable.
In the main thread (in the same method that called the thread) I used a loop that looks at the thread status, if it has finished, reads the variable and applies it where I want.
Here the code:
public class Connection{
private String HOST = "83.xx.xx.xx";
private int PORT = 5010;
private Socket socket;
private DataOutputStream dos;
private DataInputStream dis;
boolean result;
String email;
public boolean userExists(String dev) throws InterruptedException { // true = exists, false = does not exist. dev is the email to search
this.email = dev;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket(HOST, PORT);
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream((socket.getInputStream()));
dos.writeInt(1); // 1 = Sends the option for telling the server that we want to search a user
dos.writeUTF(email); //Sends the email
result = dis.readBoolean(); // Recieve if email exists or not
socket.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Couldn't connect to server");
}
}
});
thread.start();
for (int c=0; c<25; c++){ //Wait for the thread to end
if (thread.isAlive()) {
//Thread hasn't finished yet...
Thread.sleep(100);
} else if (c == 24) {
//This would be a timeout
result = false;
} else {
//Thread has finished
break;
}
}
return result; // true in case server found the email, false in case it doesn't or in case of a timeout
}
I think another possibility could be making the thread just do the connection (and another one for closing it) and saving the socket as class-level variable, so you can send and receive from the main thread, I didn't try it tho.

Peer-to-peer chat not receiving/sending messages

I am trying to create peers that are connected to each other and are able to send/receive messages to everyone that they are connected to concurrently. They are all run on the same machine. Once connecting to a peer and acquiring a socket connection, I am starting two threads, one that is reading and one that is writing. However, readLine() blocks indefinitely and I am not sure where the problem exists. The peers successfully connect to each other, but the message exchange fails. Interrupting one peer causes a "null" message to be read from the other peers connected to it.
EDIT: Using autoflush = true in PrintWriter throws "ConnectionReset" exception to the other peers connected to the interrupted peer.
I have tried waiting for the reading thread to start before sending the message, getting the socket connection from either end of the peers, storing the input/output streams in lists stored as member variables and also just passing only the socket/all streams to each thread. Also tried different ways of reading, shown in comments in the reading thread.
class ConnectionListener extends Thread{
public void run(){
try {
while (!allPeersJoined()) {
Socket socket = null;
socket = peerServer.accept();
new PeerReader(socket).start();
new PeerWriter(socket).start();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
class PeerWriter extends Thread{
PrintWriter writer;
public PeerWriter(Socket socket){
try {
this.writer = new PrintWriter(socket.getOutputStream(), true);
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void run() {
writer.println("Hello");
}
}
class PeerReader extends Thread{
BufferedReader reader;
public PeerReader(Socket socket){
try {
this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void run() {
String input = "";
System.out.println("Waiting to receive messages...");
try {
System.out.println(reader.readLine());
// while((input = reader.readLine()) != null){
// System.out.println(input);
// }
}catch (IOException e){
e.printStackTrace();
}
}
}
EDIT: Adding socket creation
Thread t = new ConnectionListener();
t.start();
// Connect to all peers
for (String peer : peers) {
new Socket("127.0.0.1", Integer.valueOf(peer));
}
You are creating multiple socket but then never use them.
Right now the ConnectionListener get your connection, send the bytes on the connected sockets, but the sockets never responds ... because you never told them to.
You should in the same way you did with ConnectionListener, create an object called
ClientConnection, that has its own writer and reader.

how can i send data to the selected client from server?

i'm building a multithread example using sockets and threads in java. the sever will get multiple Socket at same time, and when i send a message from server, i want the socket from client to go back in order to what i give.
my understanding so far is to make ArrayList but i have no idea how to use it for my purpose.
can anyone help or give me any clue to solve this problem?
following is the code:
//server socket to wait before accepting from client.
public class ServerSocketEntry {
ServerSocket ssoc;
Socket soc;
ArrayList<Socket> arrSocket = new ArrayList<Socket>();
private static final int port=4853;
public ServerSocketEntry(ServerManagement sm){
try {
ssoc = new ServerSocket(port);
System.out.println("Waiting");
while(true){
soc=ssoc.accept();
arrSocket.add(soc);
System.out.println("Accepted: "+soc);
ServerSocketThread sth = new ServerSocketThread(soc,sm);
sth.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ServerManagement sm = new ServerManagement();
new ServerSocketEntry(sm);
}
}
//threadClass using readObject(), writeObject() method.
public class ServerSocketThread extends Thread {
Socket soc;
ObjectOutputStream oos;
ObjectInputStream ois;
ServerManagement sm;
Food food;
public ServerSocketThread(Socket soc,ServerManagement sm) {
this.soc=soc;
this.sm=sm;
try {
ois= new ObjectInputStream(soc.getInputStream());
oos= new ObjectOutputStream(soc.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run(){
Command com;
while(true){
try {
com = (Command) ois.readObject();
if(com.getCommand()==Command.Member_Check){
Member member = (Member) com.getObj();
System.out.println("thread: "+member);
if(sm.checkMember(member)){
com.setCommand(Command.Command_OK);
}else{
com.setCommand(Command.Command_Fail);
}
}else if(com.getCommand()==Command.LogIn_Check){
Member member = (Member) com.getObj();
if(sm.checkLogIn(member)){
com.setCommand(Command.Command_OK);
}else{
com.setCommand(Command.Command_Fail);
}
}else if(com.getCommand()==Command.Food_Check){
ArrayList<Food> serverArrFood = com.getFoodOrder();
if(sm.checkFood(serverArrFood)){
com.setCommand(Command.Command_OK);
}else{
com.setCommand(Command.Command_Fail);
}
}
oos.writeObject(com);
oos.flush();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Then you may use a hash map to store the connected clients and it will be easy to get a specific client from the map and send message to that. Use a nickname of the client as the key and socket as a value at the time when a new client connects to the sever. Put these values into the map. For Example:
Map<String, Socket> clients = new HashMap();
clients.put(nickname, clientSocket);
While writing simply get that specific client by its key.
clients.get(nickname);
and write to its output stream. When one client sends message to a specific client, it should send the receiver's nickname as part of the message to the server.

Java TCP sockets, sending and receiving objects in a thread

I'm a a beginner programmer, currently stuck on a java project. I have a fully working singleplayer minesweeper game, object-oriented, and I'm trying to implement a TCP multiplayer function. The game has a control class, which handles the view, game field, timer, labels, has the action listeners, etc.
For multiplayer, I'm trying to make a separate thread, which has the Socker and the ServerSocket, and depending on the parameters passed on by the constructor, acts as a host or client. While running, it should be trying to read my custom Packet class from the input stream, and another method can send packets. Here is the code:
public class MultiThread extends Thread {
GameControl gc;
ServerSocket servSocket;
Socket socket;
Packet data;
ObjectInputStream incoming;
ObjectOutputStream outgoing;
Boolean isHost;
Boolean commEnd;
public MultiThread(GameControl gc, Boolean isHost) {
this.gc = gc;
this.isHost = isHost;
this.commEnd = false;
gc.chatDialog.setVisible(true);
}
public void run() {
try {
if (isHost) {
servSocket = new ServerSocket(1234);
gc.chatDialog.status.setText("Awaiting connection...");
socket = servSocket.accept();
gc.chatDialog.status.setText("Connected.");
incoming = new ObjectInputStream(socket.getInputStream());
outgoing = new ObjectOutputStream(socket.getOutputStream());
}
else if (!isHost){
socket = new Socket("localhost", 1234);
if (socket.isConnected()) {
gc.chatDialog.status.setText("Connected.");
incoming = new ObjectInputStream(socket.getInputStream());
outgoing = new ObjectOutputStream(socket.getOutputStream());
}
else {
gc.chatDialog.status.setText("No connection.");
}
}
while (!commEnd) {
try {
Thread.sleep(100);
data = (Packet)incoming.readObject();
System.out.println(data.msg);
gc.chatDialog.chatArea.append(data.getMsg());
}
catch (IOException e) {e.printStackTrace();}
}
System.out.println("asd");
gc.chatDialog.status.setText("No connection");
incoming.close();
outgoing.close();
socket.close();
servSocket.close();
}
catch (Exception e) {e.printStackTrace();}
}
public void sendPacket(Packet p) {
try {
outgoing.writeObject(p);
}
catch (IOException e) {e.printStackTrace();}
}
}
The connection gets established on localhost, but I'm getting an exception thrown when trying to initialize the incoming and outgoing fields.
Sorry if the code is a mess, I get the feeling I'm in some serious misunderstanding, so any help is appreciated.

Categories

Resources