我正在尝试实现一个聊天应用程序,其中两个用户(客户端)可以在彼此之间发送和接收消息。我有两个类(服务器和客户端),并且可以在某些情况下成功地在客户端之间发送消息。我现在有两个问题。
第一个问题是,如果按照以下确切的顺序执行以下步骤,则只能成功传递消息:
如果切换了步骤5和6,那么第二个客户端在第一个客户端之前发送消息,第一个客户端永远不会收到该消息。所有后续消息都已正确传递,但我希望无论哪个客户端发起对话,都会传递第一条消息。
第二个问题是' End_of_Communication'串。如果任一客户端发送了“End_of_Communication”'作为消息,服务器以及两个客户端都应显示" [用户名]已断开连接",然后两个客户端都应终止。服务器应继续运行,并打印初始"侦听客户端请求"信息。
现在,断开连接消息将打印在两个客户端上,但两个客户端程序都没有实际终止。服务器不会打印任何断开连接消息,也不会转到while循环的顶部。我怀疑这是因为客户端程序没有终止,所以服务器阻塞,等待“clientThread [X] .join()'”。服务器和客户端类的代码都在下面复制/粘贴。
服务器类代码:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class Server {
public static final int MAXIMUM_DATAGRAM_SIZE = 255; // Maximum size of datagram
public static final String ECS = "End_of_Communication"; // End Communication String
public static void main(String[] args) throws IOException {
byte[] clientData1 = new byte[MAXIMUM_DATAGRAM_SIZE]; // Buffer for first client requesting to connect
byte[] clientData2 = new byte[MAXIMUM_DATAGRAM_SIZE]; // Buffer for second client requesting to connect
DatagramPacket clientPacket1 = new DatagramPacket(clientData1, clientData1.length); // Packet for first client requesting to connect
DatagramPacket clientPacket2 = new DatagramPacket(clientData2, clientData2.length); // Packet for second client requesting to connect
DatagramSocket serverSocket; // Socket for server to listen on
int serverPort; // Port to start serverSocket on
int clientPort1;
int clientPort2;
Runnable clientRun1; // Runnable object for first client requesting to connect
Runnable clientRun2; // Runnable object for second client requesting to connect
Thread clientThread1; // Thread for first client requesting to connect
Thread clientThread2; // Thread for second client requesting to connect
String clientAlias1; // Alias of first client requesting to connect
String clientAlias2; // Alias of second client requesting to connect
// Check for correct # of arguments
if(args.length != 1)
throw new IllegalArgumentException("Parameter(s): <Port>");
// Initialize serverPort and serverSocket
serverPort = Integer.parseInt(args[0]);
serverSocket = new DatagramSocket(serverPort);
// Loop forever and accept requests from clients
while(true) {
// Block until a client request is received, and get client alias and
System.out.println("[" + getTime() + "] | Listening for client requests... |");
serverSocket.receive(clientPacket1);
clientAlias1 = new String(clientPacket1.getData());
clientPort1 = clientPacket1.getPort();
System.out.println("[" + getTime() + "] | Connected to first client <" + clientAlias1
+ "> with socket address [" + clientPacket1.getSocketAddress() + "] |");
// Block until a second client request is received, and get its alias
serverSocket.receive(clientPacket2);
clientAlias2 = new String(clientPacket2.getData());
clientPort2 = clientPacket2.getPort();
System.out.println("[" + getTime() + "] | Connected to second client <" + clientAlias2
+ "> with socket address [" + clientPacket2.getSocketAddress() + "] |");
// Send clientAlias2 to first client
clientData2 = clientAlias2.getBytes();
clientPacket1.setData(clientData2);
serverSocket.send(clientPacket1);
// Send clientAlias1 to second client
clientData1 = clientAlias1.getBytes();
clientPacket2.setData(clientData1);
serverSocket.send(clientPacket2);
// Send second client's port to first client
clientData2 = String.valueOf(clientPort2).getBytes();
clientPacket1.setData(clientData2);
serverSocket.send(clientPacket1);
clientData1 = String.valueOf(clientPort1).getBytes();
clientPacket2.setData(clientData1);
serverSocket.send(clientPacket2);
// Create a new thread for each client request received
clientRun1 = new ServerThread(serverSocket, clientPacket1, clientPacket2, clientAlias1);
clientThread1 = new Thread(clientRun1);
clientRun2 = new ServerThread(serverSocket, clientPacket2, clientPacket1, clientAlias2);
clientThread2 = new Thread(clientRun2);
// Start each thread
clientThread1.start();
clientThread2.start();
// Wait for threads to finish before looping again
try{
clientThread1.join();
clientThread2.join();
} catch(InterruptedException interrupt) {
System.out.println("InterruptedException: " + interrupt);
}// End try/catch block
}// End while loop
}// End main
private static String getTime() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
return dateFormat.format(date);
}
}// End Server
/*************************************End Server**************************************/
/*************************************************************************************/
/*********************************Start ServerThread**********************************/
class ServerThread implements Runnable {
protected DatagramSocket socket;
protected DatagramPacket readPacket;
protected DatagramPacket writePacket;
protected InetAddress readAddress;
protected InetAddress writeAddress;
protected int readPort;
protected int writePort;
protected String userName;
public ServerThread(DatagramSocket serverSocket, DatagramPacket readPacket, DatagramPacket writePacket, String userName) {
this.socket = serverSocket;
this.readPacket = readPacket;
this.writePacket = writePacket;
this.readAddress = readPacket.getAddress();
this.writeAddress = writePacket.getAddress();
this.readPort = readPacket.getPort();
this.writePort = writePacket.getPort();
this.userName = userName;
}
public void run() {
try {
String message;
byte[] readBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
byte[] writeBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
while(true) {
// Create byte array to read data from packet into
readBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
readPacket = new DatagramPacket(readBytes, readBytes.length, readAddress, readPort);
// Block until packet is received, and extract its data
socket.receive(readPacket);
if(readPacket.getPort() == writePort)
continue;
message = new String(readPacket.getData());
if(message.equals(Server.ECS))
System.out.println("[" + getTime() + "] | <" + userName + "> has disconnected. |");
readBytes = Arrays.copyOfRange(readPacket.getData(), readPacket.getOffset(), readPacket.getOffset()+readPacket.getLength());
// Create byte array to write extracted data to
writeBytes = new byte[Server.MAXIMUM_DATAGRAM_SIZE];
writeBytes = readBytes;
writePacket = new DatagramPacket(writeBytes, writeBytes.length, writeAddress, writePort);
// Send the packet to its destination
socket.send(writePacket);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getTime() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
return dateFormat.format(date);
}
}
客户类代码:
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Client {
public static final int MAXIMUM_DATAGRAM_SIZE = 255; // Maximum size of datagram
public static final String ECS = "End_of_Communication"; // End Communication String
public static void main(String[] args) throws IOException {
BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in)); // BufferedReader to get user input
byte[] myData = new byte[MAXIMUM_DATAGRAM_SIZE];
byte[] clientData = new byte[MAXIMUM_DATAGRAM_SIZE];
DatagramSocket clientSocket; // Socket for this client to connect to server
DatagramPacket myDataPacket;
DatagramPacket clientDataPacket;
InetAddress serverIP; // IP address of server
int serverPort; // Port that server is listening on
int clientPort; // Port to send messages to
WriteThread write; // Thread to write data to the server
ReadThread read; // Thread to read data from the server
String userName; // Alias to use for this client
String clientName; // Alias to use for other client
// Check for correct # of arguments
if((args.length < 1) || (args.length > 2))
throw new IllegalArgumentException("Parameter(s): <Server> [<Port>]");
// Create DatagramSocket on specified port and IP address
serverIP = InetAddress.getByName(args[0]);
serverPort = Integer.parseInt(args[1]);
clientSocket = new DatagramSocket();
// Connect the socket the server
clientSocket.connect(serverIP, serverPort);
// Collect data to connect
System.out.println("Please enter username(No Spaces): [Guest]");
userName = userInput.readLine();
if(userName.isEmpty())
userName = "Guest";
System.out.println("| Username set to <" + userName + ">. Sending to server... |");
myData = userName.getBytes();
// Send packet with userName to server
myDataPacket = new DatagramPacket(myData, myData.length, serverIP, serverPort);
clientSocket.send(myDataPacket);
// Create packet to receive data about the other client from the server
clientDataPacket = new DatagramPacket(clientData, clientData.length);
clientDataPacket.setLength(MAXIMUM_DATAGRAM_SIZE);
clientSocket.receive(clientDataPacket);
clientName = new String(clientDataPacket.getData());
clientData = new byte[MAXIMUM_DATAGRAM_SIZE];
clientDataPacket = new DatagramPacket(clientData, clientData.length);
clientDataPacket.setLength(MAXIMUM_DATAGRAM_SIZE);
clientSocket.receive(clientDataPacket);
clientPort = Integer.parseInt((new String(clientDataPacket.getData())).trim());
// Create and start threads to write to and read data from the server
write = new WriteThread(clientSocket, serverPort, userName);
read = new ReadThread(clientSocket, clientName);
write.start();
read.start();
// Wait for threads to finish
try {
write.join();
read.join();
} catch(InterruptedException interrupt) {
System.out.println("InterruptedException: " + interrupt);
}// End try/catch block
}// End main
}// End Client
/*************************************End Client**************************************/
/*************************************************************************************/
/**********************************Start WriteThread**********************************/
class WriteThread extends Thread implements Runnable {
protected InetAddress serverIP; // IP address of the server
protected int serverPort; // Port server is listening on
protected DatagramSocket writeSocket; // DatagramSocket to SEND data to server
protected String userName;
public WriteThread(DatagramSocket clientSocket, int serverPort, String userName) {
this.writeSocket = clientSocket;
this.serverPort = serverPort;
this.serverIP = clientSocket.getInetAddress();
this.userName = userName;
}
public void run() {
try {
BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in));
String writeString;
byte[] writeBytes;
DatagramPacket writePacket;
while(true) {
writeBytes = new byte[Client.MAXIMUM_DATAGRAM_SIZE];
writeString = userInput.readLine();
writeBytes = writeString.getBytes();
writePacket = new DatagramPacket(writeBytes, writeBytes.length, serverIP, serverPort);
writeSocket.send(writePacket);
if((writeString).equals(Client.ECS))
break;
System.out.println("[" + getTime() + "]<" + userName + "> " + new String(writePacket.getData()));
}// End while
// End_of_Communiation received, print disconnect message
System.out.println("[" + getTime() + "] | <" + userName + "> has disconnected. |");
writeBytes = new byte[Client.MAXIMUM_DATAGRAM_SIZE];
writeBytes = writeString.getBytes();
writePacket = new DatagramPacket(writeBytes, writeBytes.length, serverIP, serverPort);
writeSocket.send(writePacket);
} catch (IOException ex) {
System.out.println("IOException: " + ex);
}// End try/catch block
}// End run()
private String getTime() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
return dateFormat.format(date);
}
}// End writeThread
/***********************************End WriteThread***********************************/
/*************************************************************************************/
/**********************************Start ReadThread***********************************/
class ReadThread extends Thread implements Runnable {
protected InetAddress serverIP; // IP address of the server
protected int serverPort; // Port server is listening on
protected DatagramSocket clientSocket; // DatagramSocket to READ data to server
protected String clientName;
public ReadThread(DatagramSocket clientSocket, String clientName) throws SocketException {
this.serverIP = clientSocket.getInetAddress();
this.serverPort = clientSocket.getPort();
this.clientSocket = clientSocket;
this.clientName = clientName;
}
public void run() {
try {
byte[] readData = new byte[Server.MAXIMUM_DATAGRAM_SIZE]; // Buffer for data READ from server
DatagramPacket readPacket; // Packet to READ data to server
String readMessage; // String of the message READ from server
// Loop until user requests disconnect
while(true) {
// Set up datagram packet to READ from server
readPacket = new DatagramPacket(readData, readData.length);
// Wait for a packet to READ from server
clientSocket.receive(readPacket);
// Extract and print message READ from server
readMessage = new String(readPacket.getData(), 0, readPacket.getLength());
if(readMessage.equals(Client.ECS))
break;
System.out.println("[" + getTime() + "]<" + clientName + "> " + readMessage);
}// End while
// End_of_Communication received, exit
System.out.println("[" + getTime() + "] | <" + clientName + "> has disconnected. |");
} catch(IOException ex) {
System.err.println("IOException caught: " + ex);
}// End try/catch block
return;
}// End run
private String getTime() {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
return dateFormat.format(date);
}
}// End readThread
答案 0 :(得分:0)
我看到的第一件事是你没有关闭你的插座。这意味着即使没有数据传输,连接仍然存在。
对于任何IO来说,正确处理关闭行为非常重要,因此连接不会保持活动状态。这通常是通过try,catch,finally块完成的。以您的ReadThread
为例
try {
// Loop until user requests disconnect
while(true) {
//...bla bla...
}// End while
// End_of_Communication received, exit
System.out.println("[" + getTime() + "] | <" + clientName + "> has disconnected. |");
} catch(IOException ex) {
System.err.println("IOException caught: " + ex);
} finally {
// here we want to close the socket.
//Even if an exception is thrown we always want to make sure that the client connection is terminated.
clientSocket.close();
}
我敢打赌,如果你关闭所有客户,你的问题就会消失。此外,在完成资源完成后养成正确关闭资源的习惯也很重要。
如果你想了解更多关于尝试的信息,请抓住最后一个阻止,你可以在这里阅读http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html