具有两个并发用户的Java UDP聊天应用程序
我正在尝试实现一个聊天应用程序,其中两个用户(客户端)可以相互发送和接收消息。我有两个类(服务器和客户端),在某些情况下可以在客户端之间成功地发送消息。我现在对这个项目有两个问题 第一个问题是,仅当以下步骤按此确切顺序执行时,消息才会成功传递:具有两个并发用户的Java UDP聊天应用程序,java,multithreading,udp,chat,datagram,Java,Multithreading,Udp,Chat,Datagram,我正在尝试实现一个聊天应用程序,其中两个用户(客户端)可以相互发送和接收消息。我有两个类(服务器和客户端),在某些情况下可以在客户端之间成功地发送消息。我现在对这个项目有两个问题 第一个问题是,仅当以下步骤按此确切顺序执行时,消息才会成功传递: 启动服务器类的一个实例,然后启动客户机类的两个实例 输入其中一个客户端的用户名(从此处称为client1) 输入另一个客户端的用户名(从此处称为客户端2) 从连接到服务器的第一个客户端(客户端1)发送消息 从连接到服务器的第二个客户端(client2)发
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.io.IOException;
导入java.net.DatagramPacket;
导入java.net.DatagramSocket;
导入java.net.InetAddress;
导入java.text.DateFormat;
导入java.text.simpleDataFormat;
导入java.util.array;
导入java.util.Date;
公共类服务器{
public static final int MAXIMUM_DATAGRAM_SIZE=255;//数据报的最大大小
public static final String ECS=“结束通信”;//结束通信字符串
公共静态void main(字符串[]args)引发IOException{
byte[]clientData1=新字节[最大数据报大小];//第一个请求连接的客户端的缓冲区
byte[]clientData2=新字节[最大数据报大小];//用于请求连接的第二个客户端的缓冲区
DatagramPacket clientPacket1=新的DatagramPacket(clientData1,clientData1.length);//第一个请求连接的客户端的数据包
DatagramPacket clientPacket2=新的DatagramPacket(clientData2,clientData2.length);//第二个请求连接的客户端的数据包
DatagramSocket serverSocket;//服务器要侦听的套接字
int serverPort;//要在其上启动serverSocket的端口
int客户端端口1;
int客户端端口2;
Runnable clientRun1;//第一个请求连接的客户端的Runnable对象
Runnable clientRun2;//请求连接的第二个客户端的Runnable对象
Thread clientThread1;//第一个请求连接的客户端的线程
Thread clientThread2;//第二个客户端请求连接的线程
String clientAlias1;//请求连接的第一个客户端的别名
String clientAlias2;//请求连接的第二个客户端的别名
//检查参数是否正确
如果(args.length!=1)
抛出新的IllegalArgumentException(“参数:”);
//初始化服务器端口和服务器套接字
serverPort=Integer.parseInt(args[0]);
serverSocket=新的DatagramSocket(服务器端口);
//永远循环并接受来自客户端的请求
while(true){
//阻止,直到收到客户端请求,并获取客户端别名和
System.out.println(“[”+getTime()+“]|侦听客户端请求…|”);
serverSocket.receive(clientPacket1);
clientAlias1=新字符串(clientPacket1.getData());
clientPort1=clientPacket1.getPort();
System.out.println(“[”+getTime()+“])|连接到具有套接字地址[“+clientPacket1.getSocketAddress()+”]|”的第一个客户端;
//阻止,直到收到第二个客户端请求,并获取其别名
serverSocket.receive(clientPacket2);
clientAlias2=新字符串(clientPacket2.getData());
clientPort2=clientPacket2.getPort();
System.out.println(“[”+getTime()+“])|连接到具有套接字地址[“+clientPacket2.getSocketAddress()+”]|”的第二个客户端;
//将clientAlias2发送到第一个客户端
clientData2=clientAlias2.getBytes();
clientPacket1.setData(clientData2);
发送(clientPacket1);
//将clientAlias1发送到第二个客户端
clientData1=clientAlias1.getBytes();
clientPacket2.setData(clientData1);
发送(clientPacket2);
//将第二个客户端的端口发送到第一个客户端
clientData2=String.valueOf(clientPort2.getBytes();
clientPacket1.setData(clientData2);
发送(clientPacket1);
clientData1=String.valueOf(clientPort1.getBytes();
clientPacket2.setData(clientData1);
发送(clientPacket2);
//为收到的每个客户端请求创建一个新线程
clientRun1=新的ServerThread(serverSocket、clientPacket1、clientPacket2、clien
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
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();
}