我正在开发一个简单的Java聊天程序,主要是为了了解UDP以及计算机如何相互通信。
到目前为止,我已经能够设置服务器来监听客户端连接到它,我甚至能够通过服务器将消息从一个客户端重定向到另一个客户端 - 也就是说:
客户A - >服务器 - >客户B
我已经达到服务器实际发送数据包的程度(sock.send(数据包)),但问题是客户实际上并不知道"知道"听他们只知道如何发送到服务器。
我尝试为客户端设置run(),类似于我对服务器的操作,但是当我拉出两个客户端时,我的程序崩溃了,因为我试图在同一个端口上侦听。
服务器代码(请忽略所有分隔符,它只是我现在用来发送不同信息的方式):
package com.jona.chat.UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.sql.SQLException;
import java.util.TreeMap;
public class UDPServer extends Thread{
final int PORT_NUMBER = 4447;
private String separator = "~!~--//1337"; //IGNORE THIS
protected DatagramSocket sock = null;
private TreeMap<String,InetAddress> nameIPTree = new TreeMap<String,InetAddress>(); //IGNORE THIS
public static void main(String args[]) throws IOException{
UDPServer SERVER = new UDPServer();
//calls the run() method
SERVER.start();
}
public UDPServer() throws IOException{
sock = new DatagramSocket(PORT_NUMBER);
}
public void run(){
System.out.println("Waiting for Client");
while(true){
try{
//========================================================================================================
//Prepare the packet to receive data from client
//========================================================================================================
//Buffer (byte array) that will receive the client's data
byte[] buffer = new byte[512];
//Create a packet using the empty buffer and its length
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//========================================================================================================
//Receive the packet from the client, execute the statement, and get the result
//========================================================================================================
//Receive the packet
sock.receive(packet);
System.out.println("Server: Received packet from Client");
//Extract the data
String fromUser = new String(packet.getData(), 0, packet.getLength());
//Parse data
String[] instructions = fromUser.split(separator); //IGNORE THIS
//Add UserName and IP to tree
if(instructions[0].equals("LOGIN")){
System.out.println("Logged in!");
nameIPTree.put(instructions[1], packet.getAddress());
run();
}
//Send message to recipient and upload to DB
else if(instructions[0].equals("MESSAGE")){
//Create a string composed of the sender and the message
String toUser = instructions[2] + separator + instructions[3];
//Store the string in the buffer
buffer = toUser.getBytes();
//Make a new packet with the buffer, its length, the RECEPIENT'S IP (retrieved from tree, hence receiving user HAS TO BE LOGGED IN)
//and the port number the server uses
packet = new DatagramPacket(buffer, buffer.length, nameIPTree.get(instructions[2]), PORT_NUMBER+1);
//Send the packet
sock.send(packet);
System.out.println("Server: Sent result to Client: " + toUser);
}
}
catch (IOException e){
e.printStackTrace();
break;
}
}
System.out.println("Closing the socket");
sock.close();
}
}
客户端
public class UDPClient extends Thread{
final int PORT_NUMBER = 4447;
private String separator = "~!~--//1337";
public String TalkToServer(String message){
try{
//========================================================================================================
//Create a datagram socket
//========================================================================================================
DatagramSocket sock = new DatagramSocket();
//========================================================================================================
//Connect & Send to server
//========================================================================================================
//Create a byte array called buffer that will hold the instructions to be sent to the server
byte[] buffer = message.getBytes("UTF-8");
//Get the IP address to which the packet will be sent
InetAddress ipAddress = InetAddress.getByName("123.45.67");
//Create a datagram packet which is composed of the buffer (message), its length, the IP address,
//and the port (matches with server's listening port) to send the data on
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, ipAddress, PORT_NUMBER);
//same thing in both ifs, I know, I just wanted to see what it was doing
if(message.substring(0, 5).equals("LOGIN")){
System.out.println("Client: Logging in");
//Send the packet
sock.send(packet);
System.out.println("Client: Sent packet to Server\nSent: " + message);
sock.close();
return null;
}
if(message.substring(0, 7).equals("MESSAGE")){
System.out.println("Client: Sending message to server");
//Send the packet
sock.send(packet);
System.out.println("Client: Sent packet to Server\nSent: " + message);
sock.close();
return null;
}
}
catch(IOException e){System.out.print(e);}
return null;
}
}
最后,这是我试图让客户端听的方式(这是我的主要课程):
public static void main(String[] args) throws SocketException{
MainGUI listener = new MainGUI();
listener.start();
...
public MainGUI() throws SocketException{
sock = new DatagramSocket(PORT_NUMBER+1);
}
public void run(){
byte[] buffer = new byte[512];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
sock.receive(packet);
String fromUser = new String(packet.getData(), 0, packet.getLength());
//Parse data
String[] instructions = fromUser.split(separator);
System.out.println("Received message: " + instructions[1] + " from " + instructions[0]);
} catch (IOException e) { e.printStackTrace(); }
}
这是我尝试同时运行两个主电源时出现的错误(这个错误对我来说很有意义,我只是不知道还有什么可以让客户端听): / p>
Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.bind0(Unknown Source)
at java.net.AbstractPlainDatagramSocketImpl.bind(Unknown Source)
at java.net.DatagramSocket.bind(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at java.net.DatagramSocket.<init>(Unknown Source)
at com.jona.chat.UDP.UDPServer.<init>(UDPServer.java:28)
at com.jona.chat.UDP.UDPServer.main(UDPServer.java:20)
提前感谢您的帮助!
答案 0 :(得分:1)
您无法在单个计算机/网络接口上的同一端口上运行两个侦听器。我提供这个解决方案,它应该足以在同一台机器上运行服务器和多个客户端。
答案 1 :(得分:0)
你不应该为接收器&#39;重新绑定套接字。线。删除此行sock = new DatagramSocket(PORT_NUMBER+1);
。您只需要一个套接字来发送和接收数据包,因此您不应该重新绑定套接字。虽然,如果您正在等待接收数据包,这将使您的线程停止运行并且您无法发送数据包,因此如果您需要同时执行这两个数据包,则应使用两个套接字。这会解决您的问题吗?