在网上看了几个udp编程的实例,都是实现简易聊天室,但是都存在一个问题,就是通信的一方不能实现连续的发送或者是连续的接受消息java实现聊天室功能,因为发送消息,键盘的读入会导致阻塞,同理,接受消息的时候java实现聊天室功能 基于JAVA的udp编程实现简易聊天室,.()方法也会导致阻塞。
基于这个原因,我们如果把通信中一方的发送功能和接受功能用同一个main线程实现,就只能按照,发一条,收一条,这个顺序聊天,如果想解决阻塞的缺点,只能用多线程来实现。
首先,将发送数据的功能封装成函数,形参列表分别为数据报套接字,目标IP,目标端口,代码如下:
public static String sendData(DatagramSocket socket,String destAddress,int destPort) throws IOException {
Scanner in = new Scanner(System.in);
String data;
InetAddress address = InetAddress.getByName(destAddress);
// 将键盘接受到的字符转为字节数组
data = in.nextLine();
byte[] buf = data.getBytes();
// 将接受的数据封装为数据报包进行发送
// 在环回IP地址内测试,指定接收端口号为destPort
DatagramPacket senderPacket = new DatagramPacket(buf, 0,buf.length,address, destPort);
socket.send(senderPacket);
return data;
}
将接受数据的功能封装为函数,形参列表为数据报套接字,这里我们要注意,实现多线程的时候,要确保发送线程和接受线程绑定的是同一个套接字,这样才能共用一个端口号,套接字对象以构造方法的形式传入。接收数据的方法如下:
public static String receiveData(DatagramSocket socket) throws IOException {
byte[] receiverBuf = new byte[1024];
DatagramPacket receiverPacket = new DatagramPacket(receiverBuf,0,receiverBuf.length);
socket.receive(receiverPacket);
String message = new String(receiverPacket.getData(), receiverPacket.getOffset(), receiverPacket.getLength());
System.out.println(receiverPacket.getAddress() + "/" + receiverPacket.getPort() + "说: " + message);
return message;
}
继续实现两个多线程接口,基于以上两个方法。代码如下:
class SendTask implements Runnable {
private DatagramSocket socket;
private int destPort;
private String destAddress;
public SendTask(DatagramSocket socket,int destPort,String destAddress) {
this.socket = socket;
this.destAddress = destAddress;
this.destPort = destPort;
}
@Override
public void run() {
try {
String message = null;
while (true) {
message = OnePerson.sendData(socket,destAddress,destPort);
if ("再见".equals(message)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
synchronized (OnePerson.lock) {
if (OnePerson.isOffline) {
socket.close();
}
}
}
}
}
发送线程的构造方法传入了数据报套接字,目的IP地址,目的端口号。约定发送”再见“后,退出聊天,关闭资源,这里因为通信一方有发送,接收两个线程,要声明一个共享变量,同步多线程间的动作。
接收线程如下:
class ReceiveTask implements Runnable {
private DatagramSocket socket;
public ReceiveTask(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
String message;
while (true) {
message = OnePerson.receiveData(socket);
if ("再见".equals(message)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
synchronized (OnePerson.lock) {
OnePerson.isOffline = true;
}
}
}
}
主方法声明套接字对象java实现聊天室功能,启动多线程,指定自己的发送端口,指定通信对方的接收端口,通信另一方的发送端口 == 自己的接收端口,所以我们双方通信只需两个端口即可完成,如果没有实现套接字对象的绑定,就要用四个端口来实现,这个留给读者自己完成吧!
主方法如下:
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(10000);
String destAddress = "127.0.0.1";
int destPort = 10001;
Thread t1 = new Thread(new SendTask(socket,destPort,destAddress),"发送线程");
Thread t2 = new Thread(new ReceiveTask(socket),"接受线程");
t1.start();
t2.start();
}
通信另一方只需要将端口号互换 即可完成通信了。
如果我们想和小伙伴通信的话,将测试的本地环回IP地址”127.0.0.1“改为广播地址即可。
调出命令行输入,查看自己的ipv4地址和子网掩码,将主机地址改为全1,即可得到广播地址啦!
文章来源:https://blog.csdn.net/qq_43128621/article/details/109325498