Java套接字问题:消息只能传递一次
最近,我正在尝试一个练习,该练习要求设计一个具有两个基于tcp套接字的客户端的服务器。连接后,SenderClient应将用户键入的消息发送到服务器,然后服务器应将该消息转发给ReceiverClient。就像: 发送客户端->服务器->接收客户端 只有当用户类型在sender中退出时,所有程序才会终止,否则它们总是在侦听消息 现在我遇到的问题是:当我在EclipseLuna中运行这三个程序时,我发现消息只能从SenderClient->Server->ReceiverClient成功传递一次。之后,该消息将在服务器上被阻止。你们能在电脑上运行这三个程序来观察这种奇怪的现象吗。谢谢你,这里真的需要帮助Java套接字问题:消息只能传递一次,java,sockets,tcp,Java,Sockets,Tcp,最近,我正在尝试一个练习,该练习要求设计一个具有两个基于tcp套接字的客户端的服务器。连接后,SenderClient应将用户键入的消息发送到服务器,然后服务器应将该消息转发给ReceiverClient。就像: 发送客户端->服务器->接收客户端 只有当用户类型在sender中退出时,所有程序才会终止,否则它们总是在侦听消息 现在我遇到的问题是:当我在EclipseLuna中运行这三个程序时,我发现消息只能从SenderClient->Server->ReceiverClient成功传递一次。
import java.io.*;
import java.net.*;
public class Server {
public static void main (String args[]) {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
PrintWriter pw = null;
String info = null;
try {
// listening to port
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server is listening to port 8888...");
while (true) {
// respond to clients
Socket receiverSocket = serverSocket.accept();
System.out.println("receiver client connected!");
Socket senderSocket = serverSocket.accept();
System.out.println("sender client connected!");
// get input stream, read messages from sender
is = senderSocket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
info = br.readLine();
// close all resources when user types "quit"
if (info.equalsIgnoreCase("quit")) {
// close resources when user types "quit"
is.close();
isr.close();
br.close();
os.close();
pw.close();
serverSocket.close();
System.out.println("Server terminated!");
break;
}
// print out the message
if (info != null) {
System.out.println("Sender -> Server: " + info);
}
// get output stream, forward messages to receiver
os = receiverSocket.getOutputStream();
pw = new PrintWriter(os);
pw.println(info);
pw.flush();
} // end while
} catch (IOException e) {
e.printStackTrace();
} // end try...catch
} // end main method
} // end class Server
import java.io.*;
import java.net.*;
public class ReceiverClient {
public static void main (String args[]) {
InputStream is = null;
BufferedReader br = null;
String info = null;
try {
while (true) {
// create receiver socket with host and port number
Socket receiverSocket = new Socket("localhost", 8888);
// get input stream, read the information
is = receiverSocket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
info = br.readLine();
// close all resources when user types "quit"
if (info.equalsIgnoreCase("quit")) {
is.close();
br.close();
System.out.println("Receiver client terminated!");
break;
}
// print out the message
if (info != null) {
System.out.println("Sender -> Server -> Receiver: " + info);
}
receiverSocket.close();
} // end while
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} // end try...catch
} // end main method
} // end class ReceiverClient
import java.io.*;
import java.net.*;
public class SenderClient {
public static void main (String args[]) {
OutputStream os = null;
PrintWriter pw = null;
BufferedReader br = null;
String userInput = null;
try {
while (true) {
// create sender socket with host and port number
Socket senderSocket = new Socket("localhost", 8888);
// get message from user input
System.out.println("Please input a message:");
br = new BufferedReader(new InputStreamReader(System.in));
userInput = br.readLine();
// get output stream, send message to server
os = senderSocket.getOutputStream();
pw = new PrintWriter(os);
pw.println(userInput);
pw.flush();
senderSocket.close();
// close all resources when user types "quit"
if (userInput.equalsIgnoreCase("quit")) {
os.close();
pw.close();
System.out.println("Sender client terminated!");
break;
}
} // end while
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} // end try...catch
} // end main method
} // end class SenderClient
Socket receiverSocket=serverSocket.accept
ServerSocket的accept方法是一个阻塞操作:它等待传入的连接,直到该代码运行的线程等待。第一次正确执行循环是因为两个客户端连接到服务器。第二次执行循环时,您将等待另一个传入的客户端。解决方案是通过实现java.lang.Runnable接口在单独的线程中处理消息,该接口是在新启动的线程上运行的代码:
class ClientConnection implements Runnable{
private Socket sender;
private Socket receiver;
public ClientConnection(Socket sender, Socket receiver){
this.sender = sender;
this.receiver = receiver;
}
@Override
public void run(){
is = sender.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
OutputStream os = receiver.getOutputStream();
PrintWriter pw = new PrintWriter(os);
boolean clientQuit = false;
while(!clientQuit){
info = br.readLine();
if (info.equalsIgnoreCase("quit")) {
// close resources when user types "quit"
is.close();
isr.close();
br.close();
os.close();
pw.close();
serverSocket.close();
System.out.println("Server terminated!");
clientQuit = true;
} else{
pw.println(info);
pw.flush;
}
}
}
}
每当服务器获得两个传入连接时,它就会启动一个新线程来处理该连接,然后继续接受新的传入连接:
while (true) {
// respond to clients
Socket receiverSocket = serverSocket.accept();
System.out.println("receiver client connected!");
Socket senderSocket = serverSocket.accept();
System.out.println("sender client connected!");
ClientConnection connection = new ClientConnection(senderSocket, receiverSocket);
Thread connectionThread = new Thread(connection);
connectionThread.start();
}
你怎么知道接收器总是先连接?为什么在收到或发送每封邮件后都要关闭套接字,而不是让它一直打开直到对话真正结束。分配需要它,首先连接接收器。很抱歉,我没有把它描述清楚。2.起初,当我只测试单个阶段的服务器->客户端或客户端->服务器时,我试图在每条消息之后不关闭套接字,但结果总是不好。在我将socket.close移出if循环之后,当用户类型退出时,它终止,程序工作。这就是原因,尽管我真的不知道为什么会奏效。我只是在测试和修复。是的,我现在看到了我的问题。谢谢你的评论。提示:在客户端,每次连接时都打印本地端口。在服务器中,每次接受连接时都打印每个套接字的端口。您将看到发件人在第一条消息之后首先连接。不要断开连接,非常感谢。我正在努力理解这一点。你有可能重写类服务器吗?我正试图按照你的方式修改代码,但要成功编译似乎相当困难……哦,非常感谢你。但是,当我运行您的程序时,在ClientConnection.runServer.java:64处的thread-0 java.lang.NullPointerException中出现了一个异常,该异常位于java.lang.thread.runUnknown Source,感谢您的帮助,我将尝试更正它。可能与流关闭有关,正如我从文档中读到的,如果流关闭,readLine可以返回null: