
在构建基于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号