java - 在 Java 中的简单客户端-服务器应用程序中读/写

标签 java multithreading sockets

我是 Java 新手,我正在尝试学习线程和套接字。因此决定按照官方 java 教程制作简单的客户端-服务器应用程序。我的想法很简单 - 服务器等待连接,如果出现,它会使用新的套接字、输入和输出创建新线程。客户端->建立连接;带有套接字、输入、输出和 stdIn 的新线程(读取行,然后将其发送到服务器)。但我的代码出了点问题(不知道为什么)。连接已建立,没有异常。有人可以解释为什么不起作用以及如何修复它吗?另外,您对代码有什么建议吗(可能不是最佳实践之类的):

Client side:

public class Client {
    private BufferedReader reader;
    private Socket sock;
    private PrintWriter writer;

public static void main(String[] args) {
    Client client = new Client();
    client.go();
}

public void go() {
    setUpNetworking();

}

private void setUpNetworking() {
    try{
        sock = new Socket("127.0.0.1", 5000);
        System.out.println("Network established");

        ServerThread serverThread= new ServerThread(sock);
        serverThread.start();

        System.out.println("Type your message: ");
    } catch (IOException e) {
        System.out.println("Problem with establishing the network: " + e);
    }
}

class ServerThread extends Thread {
    Socket socket;
    PrintWriter out;
    BufferedReader in;
    BufferedReader stdIn;

    ServerThread(Socket socket) {
        this.socket = socket;

        try{
            out = new PrintWriter(socket.getOutputStream());
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            stdIn = new BufferedReader(new InputStreamReader(System.in));
        }catch (IOException e) {
            System.out.println("Problem with trying to read/write to server: " + e);
        }
    }
    @Override
    public void run() {
        String fromServer;
        String fromClient;
        while(true){
            try{

                if((fromServer = in.readLine()) != null) System.out.println(" " + fromServer);
                else if((fromClient = stdIn.readLine()) != null) out.println(fromClient);

            }catch(Exception e) {
                System.out.println("msg exception: " + e);
            }

        }
    }
}

}

服务器端:

public class Server {
    //Run server until keepGoing = false
    private boolean keepGoing = true;



    public static void main(String[] args) {
        Server server = new Server();
        server.go();
    }

    public void go() {

            try {
                ServerSocket serverSocket = new ServerSocket(5000);

                while(keepGoing) {

                    Socket clientSocket = serverSocket.accept();
                    ClientThread t = new ClientThread(clientSocket);
                    t.start();
                }
            } catch (IOException e) {
                System.out.println("Problem with socket/network: " + e);
            }
    }

    class ClientThread extends Thread {
        Socket clientSocket;
        PrintWriter out;
        BufferedReader in;

        ClientThread(Socket clientSocket) {
            this.clientSocket = clientSocket;

            try{
                out = new PrintWriter(clientSocket.getOutputStream());
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            } catch (IOException e) {
                System.out.println("Problem with creating in/out: " + e);
            }
        }

        @Override
        public void run() {
            String message;
            while(keepGoing) {
                try{
                    message = in.readLine();
                    out.println(message);
                    System.out.println(message);

                } catch (IOException e){
                    System.out.println("Exception while try to read line: " + e);
                }

            }
        }
    }

}

PS 我对代码做了一些更改 - 我没有创建 ClientThread 类,而是创建了新的可运行类并将该变量传递给线程类。受到这个问题的启发:"implements Runnable" vs. "extends Thread"

最佳答案

我认为问题在于服务器和客户端都在等待任何输入。服务器:

message = in.readLine();

客户:

if((fromServer = in.readLine()) != null)
   System.out.println(" " + fromServer);
else if((fromClient = stdIn.readLine()) != null)
   out.println(fromClient);

但是客户端代码已经阻塞在 fromServer = in.readLine() 部分,因此它永远无法从标准输入读取数据,因此不会向服务器发送任何内容。

您可以将尝试从标准读取转移到 setUpNetworking 方法中,紧接在 System.out.println("Type your message: "); 之后。构建一个循环,如果用户键入“exit”或“quit”或类似的内容,则退出该循环:

BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String read = "";
do {
    read = stdIn.readLine();
    System.out.println("Read from stdin: " + read);
    serverThread.send(read);

}
while (!read.equals("exit"));

ServerThread.send() 方法很简单:

void send(String string) {
    System.out.println("Sending to server: " + string);
    out.println(string);
}

但是,要使其正常工作,您必须在写入 out 后手动刷新流,或者使用以下构造函数:

out = new PrintWriter(socket.getOutputStream(), true);

请参阅PrintWriter's JavaDoc : True 表示在换行符上自动刷新。

我测试了这个设置,它对我有用。我能够从客户端向服务器发送一些内容。

然而,这只是第一步。我会将客户端和服务器的读取和写入实现为单独的线程。并且还没有实现套接字的正常关闭。更完整但简单的示例可以在 Oracle 上找到。 .

关于java - 在 Java 中的简单客户端-服务器应用程序中读/写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32299153/

相关文章:

java - Spring Tool Suite 中 Unresolved Maven 依赖关系

java - HTTP 500 网站无法显示页面

linux - 如何使用 native 网络系统从 Pd Vanilla > 0.46 控制 VLC?

Python3 - 导入和重写方法

java - 如何在 Java 中创建目录?

java - fragment Android 中的 SearchView

java - 检查用户输入是否仅是 Java 中的整数

c++ - 提高生产者消费者的并发性

c# - 使用/不使用 delegate() 启动线程

java - ResponseListener 在 snmp4j 中的工作原理