Search code examples
javamultithreadingsocketsserverclient

java server gives up on older clients whenever a new one joins


First of all i'd like to introduce my current code:

/**
 App.java:
**/
package org.example;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;


public class App 
{
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(2343);
        } catch (IOException e) {
            System.err.println("Could not listen on 2343");
        }

        try {
            while (true) {
                Socket clientSocket = serverSocket.accept();
                try {
                    new Helper(clientSocket);
                } catch (IOException e) {
                    clientSocket.close();
                }
            }
        } finally {
            serverSocket.close();
        }
    }
}


/**
 Helper.java:
**/
package org.example;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Helper extends Thread {

    public static BufferedReader br;
    public static BufferedWriter bw;
    public static String output = "";

    public Helper(Socket socket) throws IOException {
        System.out.println("user found");
        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
        start();
    }
    @Override
    public void run() {
        while (true) {
            try {
                bw.write("set");
                bw.newLine();
                bw.flush();
                System.out.println(br.readLine()+"\n"+getId());
            } catch (IOException e) {
                System.out.println("Client Lost");
                break;
            }
        }
    }
}


/**
 Cli.java
**/
package org.example2;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

class Cli {
    public static void main(String[] argv) throws Exception {
        BufferedWriter bw;
        Socket clientSocket;

        BufferedReader br;
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));


        clientSocket = new Socket("laith.com.au", 2343);
        bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8));
        br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8));
        while(true){
            String input=br.readLine();
            bw.write(inFromUser.readLine());
            bw.newLine();
            bw.flush();
        }
    }
}

Second I will show the outputs:

App.java

user found
hello world
13
hello world
13
user found
hello world
14
hello world
14
hello world
13
Client Lost
Client Lost

Cli.java (no1 all user input)

hello world
hello world
hello world
hello world

Cli.java (no2 all user input)

hello world
hello world

Transcript:

I start App:

I start First instance of Cli: user found

I type "hello world" into Cli no1: hello world (newline) 13

I type "hello world" into Cli no1 again: hello world (newline) 13

I start Second instance of Cli: user found

I type "hello world" into Cli no2: hello world (newline) 14

I type "hello world" into Cli no2 again: hello world (newline) 14

I type "hello world" into Cli no1: hello world (newline) 13

I type "hello world" into Cli no1 again:

I terminate Cli no1:

I terminate Cli no2: Client Lost (newline) Client Lost

Finally the question:

How come, whenever I add another client to connect to the server the older client is only able to send one more message before the server stops responding to it.


Solution

  • That's because br and bw in the Helper class are declared as static.

    static means that the field is shared by all instances of the class.

    As a result, when the second Helper instance is created for your second client, these shared br and bw get overwritten with reader and writer for this new connection => i.e. after that both Helper threads read from and write to this new connection.

    You see one more write from the old client because when br and bw are overwritten, the old Helper thread is already waiting inside br.readLine() for an incoming string from the first client.
    The old Helper thread reads new values of br and bw only after the line arrives.