0

I know that this question has been asked several times already. However, after following the advise in all the other questions I am still stuck as to what the problem might be.

I have a Server and a Client. A simple ping/pong program. After running the server and then the client and giving it some time to run its course, timeout exceptions start being thrown every now and then...

The timeout is there to prevent a block, however, if removed, it would cause the program to stall.

Is there a way to prevent this from occurring?

Server.java

public static void main(String args[]) {
        try {
            ServerSocket serverSocket = new ServerSocket(3000);
            while (true) {
                Socket socket = serverSocket.accept();
                String message = null;
                try {
                    socket.setSoTimeout(3000);
                    try (ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
                        message = (String) objectInputStream.readObject();
                        System.out.println("Server received " + message);
                    }
                    socket.close();
                } catch (IOException | ClassNotFoundException ex) {
                    //This exception is thrown because it hangs, but why does it hang?
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
                if ((message != null) && (message.equals("Ping"))) {
                    try {
                        Socket pongSocket = new Socket("localhost", 3000);
                        pongSocket.setSoTimeout(3000);
                        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(pongSocket.getOutputStream())) {
                            objectOutputStream.writeObject("Pong");
                            objectOutputStream.flush();
                            System.out.println("Server sent Pong");
                        }
                        pongSocket.close();
                        continue;
                    } catch (IOException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

Client.java

public static void main(String args[]) {
        while (true) {
            try {
                Socket pingSocket = new Socket("localhost", 3000);
                pingSocket.setSoTimeout(3000);
                try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(pingSocket.getOutputStream())) {
                    objectOutputStream.writeObject("Ping");
                    System.out.println("Client sent Ping");
                    objectOutputStream.flush();
                }
                pingSocket.close();
            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
Hooli
  • 1,135
  • 3
  • 19
  • 46
  • Except flush() ans swift part, have a look at this question: http://stackoverflow.com/questions/33106127/swift-socket-readline-writeline/33106252#33106252. I prefer to create a thread to process IO once serverSocket.accept() call creates a new Socket. Create a thread and pass client Socket and do your IO there – Ravindra babu Oct 20 '15 at 17:54

2 Answers2

2

You're confused about how servers and clients work with sockets. You can probably find a bunch of examples on stackoverflow and even more via Google, but the general idiom is:

server:
    create server socket
    call accept on server socket
    with accepted socket
        read request from socket
        write response to socket
        close accepted socket
        loop back to accept

client:
    create socket
    call connect on socket
    write request to socket
    read response from socket
    close socket

(Java automatically does some of those for you, for example, when creating a socket and specifying a host and port, the Socket class calls connect for you.)

In your server, you're closing the accepted socket after reading the request, then creating and connecting to a new socket to send the response, which is going to send the response to whatever's listening on localhost:3000, which is your server. Also, in your client you're writing the request but not reading the response, and doing so in a tight loop, so you're creating a lot of connections to your server, which will quickly fill the accept backlog.

Real, production applications would use threading in the server, or even use higher level libraries or even entire servers like Tomcat, but at the bottom, they're all basically doing the above, so it's good to understand that.

To demonstrate, this is what your code should look like:

Server.java

public static void main(String args[]) {
    try {
        ServerSocket serverSocket = new ServerSocket(3000);
        while (true) {
            Socket socket = serverSocket.accept();
            socket.setSoTimeout(250);
            String message = null;
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            try {
                message = (String) objectInputStream.readObject();
                System.out.println("server read: " + message);
            } catch (IOException | ClassNotFoundException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            if ((message != null) && (message.equals("Ping"))) {
                try {
                    objectOutputStream.writeObject("Pong");
                    System.out.println("server sent pong");
                } catch (IOException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            objectInputStream.close();
            objectOutputStream.close();
            socket.close();
        }
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Client.java

public static void main(String args[]) {
    while (true) {
        try {
            Socket socket = new Socket("localhost", 3000);
            String message;
            socket.setSoTimeout(250);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject("Ping");
            System.out.println("client sent ping");
            try (ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
                message = (String) objectInputStream.readObject();
                System.out.println("client read: " + message);
            }
            objectOutputStream.close();
            socket.close();
        } catch (IOException | ClassNotFoundException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            Thread.sleep(10000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
Hooli
  • 1,135
  • 3
  • 19
  • 46
blm
  • 2,379
  • 2
  • 20
  • 24
  • So what's the solution? – Hooli Oct 20 '15 at 17:56
  • It's more than just a simple fix, you'll need to modify your code to work like the above. For example, in Server.java, after reading the request, don't immediately close the socket then open a new one. Instead, check the request then send the appropriate response, then close the socket and loop back to the accept. – blm Oct 20 '15 at 17:59
  • @ravindra Thanks for doing the research I hand waved over with "You can probably find a bunch of examples". :-) I did search here, but I specified Java in my search and the answer you point to is on a question about Swift, although the answer is a good general answer so it's worth looking at. – blm Oct 20 '15 at 18:03
0

You have nothing throttling the speed of your senders. Judging at a glance, I would say you are simply overwhelming the server by sending requests faster than they can be processed. Your "server" listening on the socket can't compete with the non-throttled "client".

jgitter
  • 3,396
  • 1
  • 19
  • 26