Java TCP客户端和服务器

Java TCP客户端和服务器,java,asynchronous,tcp,io,Java,Asynchronous,Tcp,Io,我正在从事一个项目,该项目需要一个TCP客户端和服务器,服务器将消息回显给客户端。以下是此次任务的内容: 服务器应用程序应: 侦听已知IP地址和端口上的TCP连接 接受在该端口上启动的连接 从客户端接收消息并回显 继续执行此操作,直到客户端断开连接 客户申请应: 在服务器的已知IP地址和端口与服务器建立连接 以异步方式向服务器发送消息。该消息的格式为 由你选择;但是,它必须包含足够的信息,以便 从服务器返回时识别 我已经完成了服务器的编码,这就是我为客户机准备的 我的问题是: 服务器侦听已知I

我正在从事一个项目,该项目需要一个TCP客户端和服务器,服务器将消息回显给客户端。以下是此次任务的内容:

服务器应用程序应:

  • 侦听已知IP地址和端口上的TCP连接
  • 接受在该端口上启动的连接
  • 从客户端接收消息并回显
  • 继续执行此操作,直到客户端断开连接
  • 客户申请应:

  • 在服务器的已知IP地址和端口与服务器建立连接
  • 以异步方式向服务器发送消息。该消息的格式为 由你选择;但是,它必须包含足够的信息,以便 从服务器返回时识别
  • 我已经完成了服务器的编码,这就是我为客户机准备的

    我的问题是:

    • 服务器侦听已知IP和端口上的TCP连接意味着什么?在我的实现中,我使用了
      ServerSocket
      ,它接受服务器侦听的端口。我解释对了吗

    • 在我当前的TCPClient实现中,客户机向服务器发送消息,但println()似乎是一个阻塞调用,这使得它是同步的。如何使我的客户机异步

    为了简单起见,我还没有添加TCPServer的代码,如果需要,请告诉我

    更新** 根据反馈,我已经修改了TCPClient类。在收到客户机请求后,我生成了两个线程ReceiveMessage和SendMessage。这样做会给我带来以下例外:

    [Client] Message sent: Message from Client 97
    [Client] Message sent: Message from Client 98
    [Client] Message sent: Message from Client 99
    [Client] Done Sending all the messages
    java.net.SocketException: Socket closed
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at org.chanders.client.ReceiveMessage.run(ReceiveMessage.java:18)
        at java.lang.Thread.run(Thread.java:680)
    
    以下是新的客户端代码:

    public class TCPClient {
        Socket clientSocket = null;
        OutputStream out = null;
        BufferedReader in = null;
        String message = "Hello from Client";
        int messagecount = 100;
    
        // server credentials
        private static final String SERVER_ADDRESS = "localhost";
        private static final int SERVER_PORT = 50001;
    
        protected void execute() {
            try {
                clientSocket = new Socket(SERVER_ADDRESS, SERVER_PORT);
                Thread send = new Thread(new SendMessage(clientSocket.getOutputStream()));
                Thread receive = new Thread(new ReceiveMessage(clientSocket.getInputStream()));
    
                send.start();
                receive.start();
    
                //For server to wait until send and receive threads finish
                send.join();
                receive.join();
    
            } catch (UnknownHostException uhe) {
                System.err.println("Couldnt find host:  "  + SERVER_ADDRESS);
                uhe.printStackTrace();
                System.exit(-1);
    
            }catch(IOException ioe) {
                System.err.println("Couldnt get I/O:  "  + SERVER_ADDRESS);
                ioe.printStackTrace();
                System.exit(-1);
    
            }catch(InterruptedException ie) {
                System.err.println("Thread.join failed:  ");
                ie.printStackTrace();
                System.exit(-1);
            }
            finally {
                //cleanup();
            }
        }
    
        private void cleanup() {
            try {
                clientSocket.close();
            }catch(Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    
        public static void main(String[] args) {
            TCPClient client = new TCPClient();
            client.execute();
        }
    
    public class SendMessage implements Runnable {
        OutputStream out = null;
        String message = "Message from Client";
        int messageCount = 100;
    
        public SendMessage(OutputStream out) {
            this.out = out;
        }
    
        public void run() {
            PrintWriter writer = new PrintWriter(out);
            try {
    
                for (int i = 0; i < messageCount; i++) {
                    String m = message + " " + i;
                    writer.println(m);
                    System.out.println("[Client] Message sent: " + m);
                }
                System.out.println("[Client] Done Sending all the messages");
    
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(-1);
            } finally {
                cleanup();
            }
    
        }
        private void cleanup() {
            try {
                out.close();
            }catch(Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }
    
    public class ReceiveMessage implements Runnable {
        InputStream in = null;
        String message;
    
        public ReceiveMessage(InputStream in) {
            this.in = in;
        }
    
        public void run() {
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            try {
    
                while ((message = reader.readLine()) != null) {
    
                    System.out.println("[Client] Received message from Server: "
                            + message);
                }
    
                System.out.println("[Client] Done Receiving messages from Server");
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                cleanup();
            }
    
        }
        private void cleanup() {
            try {
                in.close();
            }catch(Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }
    
    公共类TCPClient{
    套接字clientSocket=null;
    OutputStream out=null;
    BufferedReader in=null;
    String message=“来自客户端的你好”;
    int messagecount=100;
    //服务器凭据
    私有静态最终字符串服务器\u ADDRESS=“localhost”;
    专用静态最终int服务器_端口=50001;
    受保护的void execute(){
    试一试{
    clientSocket=新套接字(服务器地址、服务器端口);
    线程发送=新线程(新发送消息(clientSocket.getOutputStream());
    线程接收=新线程(新接收消息(clientSocket.getInputStream());
    send.start();
    receive.start();
    //服务器等待发送和接收线程完成
    send.join();
    receive.join();
    }捕获(未知后异常uhe){
    System.err.println(“找不到主机:+服务器地址”);
    uhe.printStackTrace();
    系统退出(-1);
    }捕获(ioe异常ioe){
    System.err.println(“无法获取I/O:+服务器地址”);
    ioe.printStackTrace();
    系统退出(-1);
    }捕获(中断异常ie){
    System.err.println(“Thread.join失败:”);
    即printStackTrace();
    系统退出(-1);
    }
    最后{
    //清理();
    }
    }
    私有空间清理(){
    试一试{
    clientSocket.close();
    }捕获(例外e){
    e、 printStackTrace();
    系统退出(-1);
    }
    }
    公共静态void main(字符串[]args){
    TCPClient client=新的TCPClient();
    client.execute();
    }
    公共类SendMessage实现可运行{
    OutputStream out=null;
    String message=“来自客户端的消息”;
    int messageCount=100;
    公共发送消息(输出流输出){
    this.out=out;
    }
    公开募捐{
    PrintWriter=新的PrintWriter(输出);
    试一试{
    for(int i=0;i
    为每个客户端使用单独的线程。当您在服务器端写入内容时,必须有一个接受字符串的方法。否则它将被阻塞。粘贴您的服务器代码。

    为每个客户端使用单独的线程。当您在服务器端写入内容时,必须有一个接受字符串的方法。否则它将被阻止。请粘贴您的服务器代码。

    在此上下文中,
    异步
    可能并不意味着您不能使用println,但客户端必须能够在发送新消息时接收消息。 客户端应该创建套接字,然后创建两个线程,一个用于发送消息,另一个用于接收和打印消息

    更新

    到av