最近我正在尝试一个练习,需要基于tcp套接字设计一个具有两个客户端的服务器。在连接之后,sendclient应该发送用户输入的消息给Server,然后Server应该将该消息转发给ReceiverClient。就像:
sendclient -> Server -> ReceiverClient
只有当用户在sender中输入"quit"时,所有的程序将被终止,否则它们将一直监听消息。
现在我遇到了这样的问题:当我在Eclipse Luna中运行这三个程序时,我发现消息只能从sendclient -> 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;
}
}
}
}
当服务器收到两个传入连接时,它会触发一个新的Thread
来处理这个连接,然后继续接受新的传入连接:
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();
}