【问题标题】:Java sockets - Client doesn't read the strings from server's socketJava 套接字 - 客户端不从服务器的套接字中读取字符串
【发布时间】:2017-10-05 04:20:02
【问题描述】:

我有两个通过字符串与套接字通信的 Java 项目。一个是客户端,另一个是服务器。服务器通过“ServerSocket”接受连接,并使用新创建的“Socket”创建一个新的“Session”(线程)。

同时,客户端只有一个“Socket”,一旦连接了该套接字,客户端就会创建一个“ClientSession”(线程,与“Session”非常相似)。

我想要的是服务器通过“USERNAME”字符串询问客户端他的用户​​名,客户端用他的用户名回答。但答案永远不会回来。我认为这可能是 BufferedReader 和 PrintWriter 行在错误位置触发的同步问题。

-----------服务器代码---------------

登录类:

public class Login implements Runnable {

private ArrayList<Session> sessions;
private int port;
private Thread thread;
private ServerSocket serverSocket;
private Game game;

public Login(int port, Game game) throws Exception {
    this.sessions = new ArrayList();
    this.port = port;
    this.serverSocket = new ServerSocket(port);
    this.game = game;
    this.thread = new Thread(this);
    this.thread.start();
}

@Override
public void run() {
    while(true) {
        Socket socket;
        try {
            System.out.println("[Server Network] Waiting for a new player to log in.");
            socket = serverSocket.accept();
            sessions.add(new Session(socket,this));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

public void addPlayer(Player p) {
    this.game.addPlayer(p);
}

}

会话类:

public class Session implements Runnable {

private String username;
private Thread thread;
private Socket socket;
private BufferedReader br;
private OutputStreamWriter os;
private PrintWriter out;
private Login login;

private boolean ready;

public Session(Socket socket, Login login) throws IOException {
    this.login = login;
    this.socket = socket;
    this.ready = false;

    this.br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    this.os = new OutputStreamWriter(socket.getOutputStream());
    this.out = new PrintWriter(os);

    System.out.println("[Server network] Session created for client with ip: "+socket.getInetAddress().getHostAddress());

    this.thread = new Thread(this);
    this.thread.start();
}

public void send(String m) {
    System.out.println("[Server network] Sending message: "+m);
    out.write(m);
    out.flush();
    System.out.println("[Server network] Message sent: "+m);
}


@Override
public void run() {
    while (true) {
        if (!ready) {
            try {
                this.send("USERNAME");
                this.username = br.readLine();
                this.ready = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            String request = br.readLine();
            System.out.println(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

}

-----------客户端代码-------------

游戏类:

public class Game {

private Window window;

private LocalPlayer localPlayer;
private ArrayList<Player> players;
private Map map;

private String username;

private String serverIpAddress;
private ClientSession clientSession;
private static int port = 23123;

public Game(Window window, Map map) throws UnknownHostException, IOException {
    System.out.println("Game Launched.");

    //Asks for the server ip address and creates a session.
    //this.serverIpAddress = JOptionPane.showInputDialog(null,"Please enter the server ip address.",JOptionPane.QUESTION_MESSAGE);
    this.serverIpAddress = "localhost";

    //this.username = JOptionPane.showInputDialog(null,"What is your username?",JOptionPane.QUESTION_MESSAGE);
    this.username = "GriffinBabe";

    this.clientSession = new ClientSession(new Socket(serverIpAddress,port),this);

    this.window = window;
    this.localPlayer = new LocalPlayer(new Warrior(),this.username,'R');
    this.map = map;

}

public LocalPlayer getLocalPlayer() {
    return this.localPlayer;
}

public Map getMap() {
    return map;
}

}

ClientSession 类:

public class ClientSession implements Runnable {

private Socket socket;
private Thread thread;
private BufferedReader br;
private OutputStreamWriter os;
private PrintWriter out;
private Game game;

public ClientSession(Socket socket, Game game) throws IOException {
    this.game = game;
    this.socket = socket;

    this.br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
    this.os = new OutputStreamWriter(this.socket.getOutputStream());
    this.out = new PrintWriter(os);

    System.out.println("[Client network] Session created for server with ip: "+socket.getInetAddress().getHostAddress());

    this.thread = new Thread(this);
    this.thread.start();
}

public void send(String m) {
    System.out.println("[Client network] Sending message: "+m);
    out.write(m);
    out.flush();
    System.out.println("[Client network] Message sent: "+m);
}

@Override
public void run() {
    while(true) {
        try {
            String request = br.readLine();
            System.out.println(request);
            switch (request) {
            case "USERNAME":
                send(game.getLocalPlayer().getUsername());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

}

这里是控制台日志:

服务器(当然首先启动):

客户:

【问题讨论】:

    标签: java multithreading sockets networking


    【解决方案1】:

    在您的发送方法中,尝试将out.write(m) 更改为out.println(m)

    readLine() 方法将继续读取,直到遇到行终止符或流结尾,以先到者为准。 println() 方法会自动在您尝试发送的字符串末尾添加一个行终止符。

    https://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#println()

    【讨论】:

      【解决方案2】:

      您的服务器发送“用户名”然后等待。客户端读取下一行,并阻塞直到它接收到。所以你有一个死锁,因为服务器从不发送 EOL 字符。如果客户端读取一行,服务器应该发送一行。

      【讨论】:

      • 谢谢。这真的很简单......以防万一,有没有另一种方法可以使用 BufferedReader 读取 String 而不是 Line ?
      • 您可以读取任意数量的字符。但是如果你不知道服务器应该发送的字符串的长度,你就不知道你必须阅读多少。如果您的协议总是以服务器发送 USERNAME 开头,那么您只能读取 8 个字符。
      猜你喜欢
      • 1970-01-01
      • 2012-06-05
      • 1970-01-01
      • 2014-03-10
      • 2015-04-07
      • 2017-02-25
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多