
在构建基于TCP/IP协议的客户端-服务器应用程序时,常见的需求是实现持续的数据交换,直到客户端或服务器决定终止连接。然而,初学者在实现这一功能时常遇到困惑,尤其是在使用BufferedReader进行行读取时。
原始的服务器代码结构如下:
public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket welcomeSocket = new ServerSocket(6789);
        while (true){ // 外层循环
            Socket connectionSocket = welcomeSocket.accept(); // 接受新连接
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
            clientSentence = inFromClient.readLine(); // 读取一行
            capitalizedSentence = clientSentence.toUpperCase() + '\n';
            outToClient.writeBytes(capitalizedSentence);
        }
    }
}这段代码的问题在于,while(true)循环的每次迭代都执行welcomeSocket.accept(),这意味着服务器在处理完一个客户端的一行输入后,会立即返回到循环的开始,并尝试接受新的客户端连接。对于同一个客户端的后续输入,服务器将无法接收,因为当前连接的Socket实例已经被“抛弃”,服务器在等待新的连接。这导致了服务器只能读取每个客户端发送的第一行数据。
客户端代码也存在类似的问题,它在一个无限循环中发送数据并尝试读取响应,但没有明确的终止机制。
立即学习“Java免费学习笔记(深入)”;
为了实现单个客户端连接内的持续数据交换,服务器需要引入一个内层循环来处理来自当前连接的连续输入。同时,需要定义一个特定的指令(例如"stop")来允许客户端通知服务器终止当前连接。
修改后的服务器代码应包含一个内层while(true)循环,专门用于处理当前connectionSocket的数据。
import java.io.*;
import java.net.*;
public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket welcomeSocket = new ServerSocket(6789);
        System.out.println("Server started, waiting for clients...");
        while (true) { // 外层循环:接受新客户端连接
            Socket connectionSocket = welcomeSocket.accept();
            System.out.println("Client connected: " + connectionSocket.getInetAddress());
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
            // 内层循环:处理当前客户端的持续输入
            while (true) {
                String clientSentence;
                try {
                    clientSentence = inFromClient.readLine();
                    if (clientSentence == null) { // 客户端关闭连接
                        System.out.println("Client disconnected unexpectedly.");
                        break; // 跳出内层循环,等待新客户端
                    }
                } catch (IOException e) {
                    System.out.println("Error reading from client: " + e.getMessage());
                    break; // 读取错误,跳出内层循环
                }
                if (clientSentence.equalsIgnoreCase("stop")) {
                    System.out.println("Client requested to stop. Closing connection.");
                    break; // 收到终止指令,跳出内层循环
                }
                String capitalizedSentence = clientSentence.toUpperCase() + '\n';
                outToClient.writeBytes(capitalizedSentence);
                System.out.println("Received: '" + clientSentence + "', Sent: '" + capitalizedSentence.trim() + "'");
            }
            connectionSocket.close(); // 关闭当前客户端连接
            System.out.println("Connection to client closed.");
        }
        // welcomeSocket.close(); // 如果服务器需要完全终止,则在此处关闭
    }
}代码说明:
如果服务器不仅要终止与当前客户端的连接,而且在处理完一个客户端后希望完全停止运行,那么可以移除外层while(true)循环,并在处理完一个客户端后关闭ServerSocket。
import java.io.*;
import java.net.*;
public class TCPServerSingleClient { // 示例:仅处理一个客户端后终止的服务器
    public static void main(String[] args) throws IOException {
        ServerSocket welcomeSocket = new ServerSocket(6789);
        System.out.println("Server started, waiting for ONE client...");
        Socket connectionSocket = welcomeSocket.accept(); // 接受一个客户端连接
        System.out.println("Client connected: " + connectionSocket.getInetAddress());
        BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
        DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
        while (true) { // 处理当前客户端的持续输入
            String clientSentence;
            try {
                clientSentence = inFromClient.readLine();
                if (clientSentence == null) {
                    System.out.println("Client disconnected unexpectedly.");
                    break;
                }
            } catch (IOException e) {
                System.out.println("Error reading from client: " + e.getMessage());
                break;
            }
            if (clientSentence.equalsIgnoreCase("stop")) {
                System.out.println("Client requested to stop. Closing connection.");
                break;
            }
            String capitalizedSentence = clientSentence.toUpperCase() + '\n';
            outToClient.writeBytes(capitalizedSentence);
            System.out.println("Received: '" + clientSentence + "', Sent: '" + capitalizedSentence.trim() + "'");
        }
        connectionSocket.close(); // 关闭客户端连接
        welcomeSocket.close();    // 关闭服务器Socket,服务器完全终止
        System.out.println("Server shut down.");
    }
}客户端需要修改以发送"stop"指令,并在收到服务器关闭连接的信号时优雅地终止其自身循环。
import java.io.*;
import java.net.*;
public class Klient {
    public static void main(String[] args) throws UnknownHostException, IOException {
        String sentence;
        String modifiedSentence;
        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
        Socket clientSocket = null; // 初始化为null,方便finally块关闭
        try {
            clientSocket = new Socket("127.0.0.1", 6789);
            System.out.println("Connected to server.");
            DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            System.out.println("Enter text (type 'stop' to terminate):");
            while (true) {
                sentence = inFromUser.readLine(); // 从用户读取输入
                // 发送数据到服务器
                outToServer.writeBytes(sentence + '\n');
                outToServer.flush(); // 确保数据立即发送
                if (sentence.equalsIgnoreCase("stop")) {
                    System.out.println("Sent 'stop' command. Terminating client.");
                    break; // 发送"stop"后,客户端也应终止
                }
                // 读取服务器响应
                modifiedSentence = inFromServer.readLine();
                if (modifiedSentence == null) { // 服务器关闭连接
                    System.out.println("Server closed the connection. Terminating client.");
                    break; // 服务器断开,客户端终止
                }
                System.out.println("FROM SERVER: " + modifiedSentence);
            }
        } catch (IOException e) {
            System.err.println("Client error: " + e.getMessage());
        } finally {
            if (clientSocket != null && !clientSocket.isClosed()) {
                clientSocket.close(); // 确保客户端Socket关闭
                System.out.println("Client socket closed.");
            }
        }
    }
}代码说明:
通过遵循这些原则和代码模式,可以构建出健壮且能够优雅终止的Java TCP客户端-服务器应用程序。
以上就是Java TCP Socket通信中持续数据流与优雅终止机制的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号