实现是基于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()方法 } }
运行结果展示: