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

时间:2015-08-30 17:12:09

标签: 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类,我创建了新的runnable类并将该变量传递给线程类。灵感来自这个问题:"implements Runnable" vs. "extends Thread"

1 个答案:

答案 0 :(得分:1)

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

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 = new PrintWriter(socket.getOutputStream(), true);

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

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

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