如何停止 Java Socket 客户端不断发送 'null' 数据?
How to stop Java Socket client keeps sending 'null' data?
我创建了 2 个 Java 带有套接字的程序。我希望客户端向服务器发送连续数据。但是在消息发送到服务器之后,客户端继续向服务器发送 'null' 值(当我关闭客户端程序中的套接字时发生)。
这是我的代码:
import ...
public class MainClient {
private Socket serverSock;
private PrintStream clientOutput;
public static void main(String[] args) {
MainClient client = new MainClient();
client.runClient();
}
public void runClient() {
try {
serverSock = new Socket("127.0.0.1",8282);
clientOutput = new PrintStream(serverSock.getOutputStream());
clientOutput.println("Hello, I'm Connected.");
for (int i=0;i<5;i++) {
clientOutput.println(i + "");
clientOutput.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// try {
// serverSock.close(); It will keeps sending 'null' data to the server if I use this line.
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}
服务器端:
public class MainServer {
private ServerSocket serverSocket;
private int listenPort = 8282;
private InputStream inps;
private Socket clientSocket;
private BufferedReader clientInput;
private MainServer() {
String clientMsg = "";
try {
serverSocket = new ServerSocket(listenPort);
System.out.println("Server is Listening on " + listenPort);
clientSocket = serverSocket.accept();
clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while(clientSocket.isConnected()) {
clientMsg = clientInput.readLine();
System.out.println("Client : " + clientMsg);
}
}catch(IOException ex) {
ex.printStackTrace();
}finally {
try {
clientSocket.close();
} catch (IOException e) {}
}
}
public static void main(String[] args) {
new MainServer();
}
}
我尝试使用 clientOutput.close();
关闭客户端的 OutputStream,但它在发送 0-4 循环后将空值发送到服务器。
为了让它停止并避免客户端发送空数据,我不应该在客户端上插入 serverSock.close();
,但它会 returns SocketException。我希望客户端在完成后发送 'Closed' 消息。
总结,服务器上的输出是:
Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Client: null
Client: null
//And so on..
我想客户端程序缺少某些东西,我猜?
谢谢你的帮助:)
通常代码应该类似于
private MainServer() {
String clientMsg = "";
try {
serverSocket = new ServerSocket(listenPort);
System.out.println("Server is Listening on " + listenPort);
clientSocket = serverSocket.accept();
clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((clientMsg = clientInput.readLine()) != null) {
if(isTerminationString(clientMsg)) {
break;
}
System.out.println("Client : " + clientMsg);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
}
}
}
boolean isTerminationString(String msg) {
return msg.equals("DONE!");
}
在 isTerminationString
你检查消息是否是终止消息的地方,通信协议应该在客户端和服务器之间共享。我举了发送的例子
DONE 消息,但它可能比那更复杂。
由于关闭套接字上的 close
方法并不能保证另一部分的套接字也被关闭,因此使用 isClosed
方法可能无效并导致与您遇到的相同问题。
你的MainClient()没有问题。
MainServer() 中的 clientSocket.isConnected() 函数总是检查客户端的状态,这会导致无限循环,因此在消息 'client:4' 之后,clientInput.readLine() 应该 return 'null'.
因此,您可以使用函数 'clientSocket.isClosed()'.
检查客户端套接字是否已关闭,而不是检查客户端套接字是否已连接
用下面的代码替换 MainServer() 中的 while 循环,
while(!clientSocket.isClosed()) {
clientMsg = clientInput.readLine();
System.out.println("Client : " + clientMsg);
if(clientMsg.equals("Closed")){
clientSocket.close();
// serverSocket.close();
}
}
这将帮助您在从服务器接收到 'Closed' 消息时关闭客户端套接字,从而避免无限执行 while 循环以及打印 null 语句。
代码 "serverSocket.close()" 帮助您关闭服务器套接字,如果您需要停止端口监听,您可以在 'MainServer()' 处使用它。
如评论所述,客户端未发送 null
值。
isConnected()
方法并没有像您想象的那样做,即它 没有 告诉您套接字当前是否 "connected" 到它的对等方,至少以您认为应该的方式。 isConnected()
在套接字转换为连接状态后立即变为真,此后保持真,即使在套接字关闭后也是如此。在 Whosebug 上查看 this discussion 和其他人。
确定对等方是否已关闭连接的正确方法是尝试从套接字读取,然后检查结果以寻找关闭的证据。请阅读您正在使用的方法的 Javadocs,它们会告诉您各种 return 值的含义。对于 BufferedReader.readLine()
方法,它表示:
Returns:
A String containing the contents of the line, not including
any line-termination characters, or null if the end of the stream has
been reached
Throws:
IOException - If an I/O error occurs
因此您需要检查空 return 值以检测正常的套接字关闭,以及是否收到指示某种网络异常的 IOException。
我创建了 2 个 Java 带有套接字的程序。我希望客户端向服务器发送连续数据。但是在消息发送到服务器之后,客户端继续向服务器发送 'null' 值(当我关闭客户端程序中的套接字时发生)。 这是我的代码:
import ...
public class MainClient {
private Socket serverSock;
private PrintStream clientOutput;
public static void main(String[] args) {
MainClient client = new MainClient();
client.runClient();
}
public void runClient() {
try {
serverSock = new Socket("127.0.0.1",8282);
clientOutput = new PrintStream(serverSock.getOutputStream());
clientOutput.println("Hello, I'm Connected.");
for (int i=0;i<5;i++) {
clientOutput.println(i + "");
clientOutput.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// try {
// serverSock.close(); It will keeps sending 'null' data to the server if I use this line.
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
}
服务器端:
public class MainServer {
private ServerSocket serverSocket;
private int listenPort = 8282;
private InputStream inps;
private Socket clientSocket;
private BufferedReader clientInput;
private MainServer() {
String clientMsg = "";
try {
serverSocket = new ServerSocket(listenPort);
System.out.println("Server is Listening on " + listenPort);
clientSocket = serverSocket.accept();
clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while(clientSocket.isConnected()) {
clientMsg = clientInput.readLine();
System.out.println("Client : " + clientMsg);
}
}catch(IOException ex) {
ex.printStackTrace();
}finally {
try {
clientSocket.close();
} catch (IOException e) {}
}
}
public static void main(String[] args) {
new MainServer();
}
}
我尝试使用 clientOutput.close();
关闭客户端的 OutputStream,但它在发送 0-4 循环后将空值发送到服务器。
为了让它停止并避免客户端发送空数据,我不应该在客户端上插入 serverSock.close();
,但它会 returns SocketException。我希望客户端在完成后发送 'Closed' 消息。
总结,服务器上的输出是:
Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Client: null
Client: null
//And so on..
我想客户端程序缺少某些东西,我猜? 谢谢你的帮助:)
通常代码应该类似于
private MainServer() {
String clientMsg = "";
try {
serverSocket = new ServerSocket(listenPort);
System.out.println("Server is Listening on " + listenPort);
clientSocket = serverSocket.accept();
clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((clientMsg = clientInput.readLine()) != null) {
if(isTerminationString(clientMsg)) {
break;
}
System.out.println("Client : " + clientMsg);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
}
}
}
boolean isTerminationString(String msg) {
return msg.equals("DONE!");
}
在 isTerminationString
你检查消息是否是终止消息的地方,通信协议应该在客户端和服务器之间共享。我举了发送的例子
DONE 消息,但它可能比那更复杂。
由于关闭套接字上的 close
方法并不能保证另一部分的套接字也被关闭,因此使用 isClosed
方法可能无效并导致与您遇到的相同问题。
你的MainClient()没有问题。
MainServer() 中的clientSocket.isConnected() 函数总是检查客户端的状态,这会导致无限循环,因此在消息 'client:4' 之后,clientInput.readLine() 应该 return 'null'.
因此,您可以使用函数 'clientSocket.isClosed()'.
检查客户端套接字是否已关闭,而不是检查客户端套接字是否已连接用下面的代码替换 MainServer() 中的 while 循环,
while(!clientSocket.isClosed()) {
clientMsg = clientInput.readLine();
System.out.println("Client : " + clientMsg);
if(clientMsg.equals("Closed")){
clientSocket.close();
// serverSocket.close();
}
}
这将帮助您在从服务器接收到 'Closed' 消息时关闭客户端套接字,从而避免无限执行 while 循环以及打印 null 语句。 代码 "serverSocket.close()" 帮助您关闭服务器套接字,如果您需要停止端口监听,您可以在 'MainServer()' 处使用它。
如评论所述,客户端未发送 null
值。
isConnected()
方法并没有像您想象的那样做,即它 没有 告诉您套接字当前是否 "connected" 到它的对等方,至少以您认为应该的方式。 isConnected()
在套接字转换为连接状态后立即变为真,此后保持真,即使在套接字关闭后也是如此。在 Whosebug 上查看 this discussion 和其他人。
确定对等方是否已关闭连接的正确方法是尝试从套接字读取,然后检查结果以寻找关闭的证据。请阅读您正在使用的方法的 Javadocs,它们会告诉您各种 return 值的含义。对于 BufferedReader.readLine()
方法,它表示:
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Throws:
IOException - If an I/O error occurs
因此您需要检查空 return 值以检测正常的套接字关闭,以及是否收到指示某种网络异常的 IOException。