实现是基于UDP协议的的,两个进程(两个java程序)互相发送,并接受各自发送的数据的功能。
两个包模拟通信的两个进程(人),由于是镜像代码,只贴出一个包中的代码,通信另一方只要做发送端口、ip的修改即可;
代码顶层设计如下:
package net.oneperson;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
/*1. 实现基于UDP协议的的,两个进程(两个java程序)互相发送,并接受各自发送的数据的功能。
(可以参考课堂上edition3非多线程版本或edition4多线程版本实现,都可以哈)
*/
public class Oneperson {
//主类应该包含主要配置信息,启动首发线程;
public static boolean isSenderoff = false;
public static Object lockClose = new Object();//用来控制访问共享变量isSenderoff的锁
public static void main(String args[]) throws SocketException, UnknownHostException {
DatagramSocket datagramSocket = new DatagramSocket(10086);//定义本人收发端口
ReceiverTask receiverTask = new ReceiverTask(datagramSocket);
Thread myReceive = new Thread(receiverTask);
myReceive.start();
String targetIp="127.0.0.1";//对方的Ip,发给本机就是本地ip
int targetPort = 8888;//对方的端口
SenderTask senderTask = new SenderTask(datagramSocket,targetIp,targetPort);
Thread mySend= new Thread(senderTask);
mySend.start();
}
}
package net.oneperson;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ReceiverTask implements Runnable {
private DatagramSocket datagramSocket;
public ReceiverTask(DatagramSocket datagramSocket) {
this.datagramSocket = datagramSocket;
}
@Override
public void run() {
//准备接收数据的package
byte[] buf = new byte[1024];
int off = 0;
DatagramPacket datagramPacket = new DatagramPacket(buf, off, buf.length - off);
boolean isFinish = false;
//用包装包的接收函数一直接收数据
try {
while (true) {
isFinish = receiveData(datagramSocket, datagramPacket);
if (isFinish) break;//收到再见之前,一直收;收到再见,不再接收,转到finally判断是否可以关闭socket
}
} catch (IOException e) {
e.printStackTrace();
} finally {
while (true) {//只要发送方还没说要结束,线程一直在这里空转,等待
synchronized (Oneperson.lockClose) {
if (Oneperson.isSenderoff) {
// datagramSocket.close();//这么写也是可以的
break;
}
try {
Oneperson.lockClose.wait(100);//可以在任何对象上调用wait,阻塞的是运行该对象的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//可以关闭了
datagramSocket.close();
}
}
/*函数:用于接收数据,并在函数将其内容显示,并判断是否收到886,是的话返回true*/
private boolean receiveData(DatagramSocket datagramSocket, DatagramPacket receivePacket) throws IOException {
datagramSocket.receive(receivePacket);//接收数据包
byte[] buf = receivePacket.getData();//从数据包获得字节数据
int off = receivePacket.getOffset();//获得实际收到字节数据的起始位置
int length = receivePacket.getLength();//本次实际收到数据的长度;
//解析接收到的字节数据,并将其转化为字符串
String s = new String(buf, off, length);
System.out.println(receivePacket.getAddress() + ":" + receivePacket.getPort() + " ," + s);
if ("886".equals(s)) {
return true;
}
return false;
}
}
package net.oneperson;
import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class SenderTask implements Runnable{
private DatagramSocket socket;
private static InetAddress targetIp; //要发送的IP地址
private static int targetPort;//要发送的端口
//构造方法参数:一个socket,targetID,targetPoet 接口,目标ID,目标端口
public SenderTask(DatagramSocket socket, String targetIp,int targrtPort) throws UnknownHostException {
this.targetIp=InetAddress.getByName(targetIp);
this.targetPort=targrtPort;
this.socket = socket;
}
@Override//执行方法
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//因为是健康输入,用System.in;如果是文件,需要一个File路径或目录
String dataSend;
while(true){
try {
//发送有输入来,就一直发送
if (((dataSend =br.readLine())==null)) break;
sendDate(dataSend,socket);
if(dataSend.equals("886")){
//每次都检查自己是不是发送了886,是的话将标记位标记
synchronized (Oneperson.lockClose){
Oneperson.isSenderoff = true;
}
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//SendDate,Q1-为什么要定义成static
//这个方法是在哪里被使用?run中
//它要接收参数,发送的信息数据,发送的接口
private static void sendDate(String data,DatagramSocket datagramSocket) throws IOException {
byte [] dataBytes = data.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(dataBytes,0,dataBytes.length,targetIp,targetPort);
datagramSocket.send(datagramPacket);//send()方法
}
}
运行结果展示: