2

We created a server client relation between java (eclipse on windows/server) and android app (android studio/client). The communication seems fine, but sometimes the connecting is horrably slow, up to the point where the app and and server don't respond anymore. Yet, no real error is given and there is no pattern to when the connection goes well or when it is slow.

We looked for answers here at stack, but we could only find answers regarding the output and input streams. However, once the connection (serverSocket.accept()) is made, the program runs fine and the streams are created super fast. Thus we think the problem lies with the server side creation of sockets. The program only has to handle a maximum of 30 clients, and the only communication exists of strings (so no enormous data transfers).

Note: when one connection acceptation is slow, the next upcomming requests from clients have to wait. When it's their turn they are again randomely fast or slowly accepted by the server. All connections are made on port 8080.

The code of our server and client are given below, does anybody know why the connection is (at some random times) so slow?

SERVER:

    public void run() {
        keepGoing = true;
    try {
        serverSocket = new ServerSocket(port);

        while (keepGoing) {
            display("Server waiting for Clients on port " + port + ".");

            Socket socket = serverSocket.accept(); //<---our problem
            if (!keepGoing)     break;
            ClientThread t = new ClientThread(socket, this); //<---program doesnt reach this code when it is slow. One client thread exists for each connection.
    }catch (IOException e) {
        String msg = sdf.format(new Date())
                + " Exception on new ServerSocket: " + e + "\n";
        display(msg);
        }
    }

CLIENT THREAD CODE: (not reached if slow)

    public ClientThread(Socket socket, Server s) {
        this.server = s;
        this.socket = socket;        
    System.out.println("Thread trying to create Object Input/Output Streams");
    try {
        // make streams
        sOutput = new ObjectOutputStream(socket.getOutputStream());
        sInput = new ObjectInputStream(socket.getInputStream());

        // read user account info
        String input = (String) sInput.readObject();
        String[] accountInfo = input.split(";");
        username = accountInfo[0];
        password = accountInfo[1];
    } "catch all problems"
    }

CLIENT (android)

    Thread connect = new Thread(new Runnable() {
    @Override
        public void run()
        {
            try
            {
                socket = new Socket(ip.getText().toString(), portNr);
                sOutput = new ObjectOutputStream(socket.getOutputStream());
                sInput = new ObjectInputStream(socket.getInputStream());
            }

            catch (UnknownHostException e ){
                e.printStackTrace();
            } catch(IOException e ){
                e.printStackTrace();
            }

            "sending account information"
        }
    });
    connect.start();
    try {
        connect.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

Thanks so much!

Anne
  • 31
  • 5

4 Answers4

1

You should make the streams in the ClientThread in the run() method, before you start looping. Not in the constructor. Otherwise you are doing I/O in the accept thread, which slows it down.

I have no idea why you're creating a thread in the client only to join it immediately.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I tried relocating the creation of streams code, problem seemed to get wors. About the location of the join: I followed a tutorial (first time server client programming) and copied pieces of the code. I don't know why its there either, should I remove it? – Anne Jun 30 '16 at 15:45
  • You should remove the *thread*. It's not just about 'the location of the join'. Poor quality code whatever its source. – user207421 Jul 01 '16 at 00:58
  • Please post your current code. Edit it into your question. – user207421 Jul 01 '16 at 01:19
  • If I remove the thread, the app crashes when it tries to make a connection. "app stopped running". When removing the join(), I get the error: Attempt to invoke virtual method 'java.lang.Object java.io.ObjectInputStream.readObject()' on a null object reference – Anne Jul 01 '16 at 09:24
  • Anne, I cannot comment on code I cannot see. Please do as I requested 8 hours ago, and please now include the client code with the 'removed thread'. – user207421 Jul 01 '16 at 09:31
  • Thank you for helping me! We figured chaning our wifi connection to a mobile hotspot, see if our internet was the problem. When all tablets and computer are connected to this hotspot everything runs super smooth, so I think it's a router problem (we got a cheap thing). Once again thanks for all your tips! – Anne Jul 01 '16 at 10:31
0

You should extract your main server loop (while(keepGoing)...) into a run method and make the server implement the Runnabel interface. Then create a new Thread and start it.

Example:

public class Server implements Runnable{
    private Thread thread;
    public Server(){
        thread = new Thread(this);
        thread.start(); //I would create start() and stop() methods but for simplicity I just use thread.start()
    }

    @Override
    public void run(){
        //while....
    }
}

I hope you get what I want to say, otherwise just comment and I will upgrade my example ;)

Spitzbueb
  • 5,233
  • 1
  • 20
  • 38
  • this is already the case, I forgot to include it in the code caption, excuses :) ill update the caption. – Anne Jun 30 '16 at 14:22
0

Turns out we had a router issue. When connecting all tablets and computer to a local hotspot it ran super smooth! Tanks everyone for the help :D

Anne
  • 31
  • 5
-1

EDIT: Try a BufferedStreamReader mentioned here: Java socket performance bottleneck: where?

Instead of:

sOutput = new ObjectOutputStream(socket.getOutputStream());

Use:

sOutput = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));

and flush it with:

sOutput.flush();

Same goes for the InputStream, use BufferedInputStream.

Community
  • 1
  • 1
babadaba
  • 814
  • 5
  • 20
  • Did you add this code before or after the serverSocket.accept(); ? – Anne Jun 30 '16 at 14:21
  • After the accept, i added the code to my answer above – babadaba Jun 30 '16 at 14:23
  • Didn't help :( still no autput from the constructor of clientthread :( – Anne Jun 30 '16 at 14:28
  • Weird things... we changed our code with you suggestions, didn't work, changed it back, now it seems to run properly... I don't know anymore haha! – Anne Jun 30 '16 at 14:47
  • I've searched a bit and found out that you should use a BufferedOutputStream. Look at this link i hope it helps: http://stackoverflow.com/questions/4451410/java-socket-performance-bottleneck-where – babadaba Jun 30 '16 at 14:57
  • bufferedstreams.. tried that been there didn't help :( – Anne Jun 30 '16 at 15:20