0

I have a some sort similar problem to this, but I've I am aware that when I ask to read a line, the the sender should send an end-of-line.

What confuses me, is that in debugging, it works. Probably because the order I step over on debug (which I didn't even knew that could make a difference until now), but I want to understand it better.

I already worked with threads, but not very much.

Here is my Server class:

import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server {

    protected static List<Game> games = new ArrayList<>();
    protected static List<ServerThread> players = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        int serverPort = 8945;
        Server server = new Server();
        ServerSocket welcomeSocket = new ServerSocket(serverPort);

        while (true) {
            Socket connectionSocket = welcomeSocket.accept();
            ServerThread st = new ServerThread(server,connectionSocket);
            st.start();
            int gameId = 0;
            if(players.size()>0 && players.size()%2==0){
                gameId++;
                players.get(0).outToClient.write("START " + gameId
                        + " 123 456" +"\n");
                players.get(0).outToClient.flush();
                players.get(1).outToClient.write("START " + gameId
                        + " 456 123" +"\n");
                players.get(1).outToClient.flush();
            }
        }
    }
}

The Thread (based on this)

import java.io.*;
import java.net.Socket;

public class ServerThread extends Thread {
    protected Server server;
    protected Socket socket;
    protected String playerName;   
    protected BufferedReader inFromClient;
    protected BufferedWriter outToClient;

    public ServerThread(Server server, Socket clientSocket) throws IOException {
        this.server = server;
        this.socket = clientSocket;
        this.inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.outToClient = new BufferedWriter(new InputStreamReader(socket.getOutputStream()));
    }

    public void run() {
        while (true) {
            try {
                String line = inFromClient.readLine();
                if(line != null) {
                    String[] clientCommand = line.split(" ");
                    String commandType = clientCommand[0];
                    if (!commandType.equalsIgnoreCase("QUIT")) {
                        switch (commandType) {
                            case "JOIN":
                                playerName = clientCommand[1];
                                System.out.println(playerName + " joined");
                                Server.players.add(this);
                                break;
                            case "PLAY":
                                //nothing yet
                                break;
                            case "MSG":
                                //nothing yet
                                break;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }
    }

And the Client:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class Client {

    private static int gameID;
    private static int order;
    private static String opponent;

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.out.println("Usage: java Client <serverIp>");
            System.exit(1);
        }
        String serverIP = args[0];
        int serverPort = 8945;
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
        Socket clientSocket = new Socket(serverIP, serverPort);
        BufferedWriter outToServer = new OutputStreamWriter(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

        String line = inFromUser.readLine();
        String[] commandSentence = line.split(" ");
        String userCommandType = commandSentence[0];
        while (!userCommandType.equals("/exit")){
            switch (userCommandType){
                case "/enter":
                    String nickname = commandSentence[1];
                    outToServer.write("JOIN "+ nickname + '\n');
                    outToServer.flush();
                    while (true){
                        String serverLine = inFromServer.readLine();
                        String[] serverCommand = serverLine.split(" ");
                        String serverCommandType = serverCommand[0];
                        if(serverCommandType.equalsIgnoreCase("START")){
                            gameID = Integer.parseInt(serverCommand[1]);
                            order = Integer.parseInt(serverCommand[2]);
                            opponent = serverCommand[3];
                            System.out.printf("%5s %5s %5s",gameID,order,opponent);
                            break;
                        }                            
                    }
                case "/play":
                    //nothing yet
                    break;
                case "/msg":
                    //nothing yet
                    break;
            }
        }
    }
}

It looks like it enter a deadlock somewhere, and for some reason, never enter that if on Serverclass which send data to the clients, unless running in debug

(BTW, I am using get(0) and get(1) like that for test purposes only)

EDIT: Ok, my silly mistake is that I forget to add outToServer.flush(); when the Client is sending data to Server. But my main problem persist, when I create two clients by typing "/enter <nickname>" to each one, when the last one is added to the list, it is expected to enter that if statement on Server.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Patrick Bard
  • 1,804
  • 18
  • 40
  • Your program description is vague. What do you mean by "deadlock"? What actually happens, or doesn't happen? Which `if` is that never gets entered, the `!st.isAlive()` one? – David Schwartz Jun 11 '15 at 11:40
  • Sorry for that. It depends now, I'd say yes when I started the question. But as @EJP said, I've changed `DataOutputStream` to `BufferedReader`, now it hangs even earlier. I couldn't test very much now, but it looks like it happens when it tries to `readLine()` at ServerThread. – Patrick Bard Jun 11 '15 at 11:45
  • Why would you expect that `if` to be entered? Why wouldn't the thread be alive? – David Schwartz Jun 11 '15 at 11:49
  • Sorry, I didn't have the `while(true)` before, that's why. – Patrick Bard Jun 11 '15 at 11:51
  • You just test for the number of players when a socket is opened. But your test is immediately after the socket is established and probably before the client sent the JOIN. – gfelisberto Jun 11 '15 at 12:15
  • I can understand that, but I am not sure I know exactly how to correct it. I feel a little dumb now. – Patrick Bard Jun 11 '15 at 12:19

2 Answers2

1

the one issue is at Client's Code at the line where you send the command to the server. The String that you are sending has very small length , so it need a outToServer.flush(); to work properly

AntJavaDev
  • 1,204
  • 1
  • 18
  • 24
  • Yeah, I just figure that out. But that does not prevent my main problem. It does not enter the `if(players.size()>0 && players.size()%2==0)` when expected to. – Patrick Bard Jun 11 '15 at 12:07
  • yes i am checking that line now , give me some time – AntJavaDev Jun 11 '15 at 12:34
  • ok got resolved , youll have to open 3 clients , in order to enter that loop , because you have the if statement in the main thread , so its checking the list.size() , and the list.size() got refreshed some time later by the server thread, thus the main thread will only enter the if after the 3d client – AntJavaDev Jun 11 '15 at 12:38
  • I need to create a Game Object every time I got a pair of users. I can't depend on a third user for the others to play. – Patrick Bard Jun 11 '15 at 12:54
  • yes what you have designed do not match with what you want to do. the first problem is that you try to serve the client in the main thread and not in the thread that is responsible for the specified client – AntJavaDev Jun 11 '15 at 13:09
  • I used to threat in the thread, but that message only is sent when a game is created, which happens when a pair of users joined, and the server knows the pair. But yeah, I am thinking in a way to redesign it actually. – Patrick Bard Jun 11 '15 at 13:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/80284/discussion-between-patrick-bard-and-antjavadev). – Patrick Bard Jun 11 '15 at 13:18
0

Get rid of the ready() test. There are few correct uses of it. Just let the following read block.

NB: Don't mix streams with readers and writers. If you're using BufferedInputStream to read, you should be using BufferedOutputStream to write.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I add the `ready()` check because at least that way it would read correctly, before it was hanging while trying to read. Maybe it was the same problem with Input and Output which I didn't noticed. I got that part of the code (input and output mixed) from a template my Professor gave me... – Patrick Bard Jun 11 '15 at 05:34
  • Is there any thing I should consider before choosing from `DataInputStream` and `DataOutputStream` from `BufferedInputStream` and `BufferedOutputStream`. Which pair should I use? – Patrick Bard Jun 11 '15 at 05:36