【问题标题】:TCP client and serverTCP 客户端和服务器
【发布时间】:2012-08-30 19:27:48
【问题描述】:

我正在开发一个需要 TCP 客户端和服务器的项目,其中服务器将消息回显给客户端。以下来自作业:

服务器应用程序应:

  1. 侦听已知 IP 地址和端口上的 TCP 连接
  2. 接受在该端口上发起的连接
  3. 从客户端接收消息并回显它们
  4. 继续执行此操作,直到客户端断开连接。

客户端应用程序应:

  1. 在其众所周知的 IP 地址和端口与服务器建立连接
  2. 以异步方式向服务器发送消息。消息的格式是 你的选择;但是,它必须包含足够的信息才能使其成为 从服务器返回时被识别。

我已经完成了服务器的编码,这就是我为客户端想出的。

我的问题:

  • 服务器侦听已知 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);
        }
    }
}

【问题讨论】:

    标签: java asynchronous tcp io


    【解决方案1】:

    在这种情况下,Asynchronous 可能并不意味着您不能使用 println,而是客户端必须能够在发送新消息时接收消息。 客户端应创建套接字,然后创建两个线程,一个用于发送消息,另一个用于接收和打印消息。

    更新

    为避免异常,请使用 clientSocket.shutdownOutput() 而不是关闭输出流。 您可以将 send 代码移回主线程,并为 receive 代码保留一个单独的线程,或者在加入 send 后调用 shutdownOutput()线。无论哪种方式更适合您。

    【讨论】:

      【解决方案2】:

      为每个客户端使用单独的线程。当你写东西时,在服务器端,必须有一个接受字符串的方法。否则会阻塞。粘贴您的服务器代码。

      【讨论】:

      • 问题似乎是关于如何使其异步。
      【解决方案3】:

      众所周知的端口是专门为特定协议指定的端口号,例如 80 用于 HTTP,443 用于 HTTPS。您是否打算实施特定的协议?如果是,我建议您使用该协议的端口号。维基百科在这里有一个众所周知的端口号列表: http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

      【讨论】:

        【解决方案4】:

        如果这是一项专业任务(而不是一些家庭作业),那么我强烈推荐Netty Server,它基本上是一个 NIO 客户端服务器框架。它显着简化/简化了此类的开发。

        请务必查看他们的 documentation,因为它提供了完全实现问题中所述的服务器/客户端功能的示例。

        如果这是一个家庭作业,那么this example 应该提供所有必要的详细信息。另请查看Oracle resources

        【讨论】:

        • 这是一个家庭作业。我不需要我们使用外部框架。
        • 已添加指向一组相关示例的链接。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-25
        • 1970-01-01
        • 2016-07-28
        • 2019-02-26
        • 2013-08-20
        • 2012-01-04
        相关资源
        最近更新 更多