八、UDP
1.在Java中操纵UDP 使用位于JDK中Java.net包下的DatagramSocket和DatagramPacket类,可以非常方便地控制用户数据报文。
2.DatagramSocket类:创建接收和发送UDP的Socket实例
DatagramSocket():创建实例。通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。
DatagramSocket(int port):创建实例,并固定监听Port端口的报文。
DatagramSocket(int port, InetAddress localAddr):这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文
receive(DatagramPacket d):接收数据报文到d中。receive方法产生一个“阻塞”。
send(DatagramPacket d):发送报文d到目的地。
setSoTimeout(int timeout):设置超时时间,单位为毫秒。
close():关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Sock
注意:
1.在创建DatagramSocket类实例时,如果端口已经被使用,会产生一个SocketException的异常抛出,并导致程序非法终止,这个异常应该注意捕获。
2.“阻塞”是一个专业名词,它会产生一个内部循环,使程序暂停在这个地方,直到一个条件触发。
3.DatagramPacket:用于处理报文,将byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成byte数组。
DatagramPacket(byte[] buf, int length, InetAddress addr, int port):从buf数组中,取出length长的数据创建数据包对象,目标是addr地址,port端口。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port):从buf数组中,取出offset开始的、length长的数据创建数据包对象,目标是addr地址,port端口。
DatagramPacket(byte[] buf, int offset, int length):将数据包中从offset开始、length长的数据装进buf数组。
DatagramPacket(byte[] buf, int length):将数据包中length长的数据装进buf数组。
getData():它从实例中取得报文的byte数组编码。
(一)、发送消息
发短信。不用连接,但是需要对方的地址
发送端
package com.net; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; //不需要连接服务器 public class UdpClientDemo01 { public static void main(String[] args) throws Exception { //1.建立一个socket DatagramSocket socket = new DatagramSocket(); //2.建个包 String msg = "Hello,服务器!"; //3.发送给谁 InetAddress localhost = InetAddress.getByName("localhost"); int port = 9090; //数据,数据的长度起始,要发送给谁 DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length,localhost,port); //3.发送包 socket.send(packet); //4.关闭流 socket.close(); } }
接收端
package com.net; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; //需要等待客户端的连接!!! public class UdpServerDemo01 { public static void main(String[] args) throws Exception { //开放端口 DatagramSocket socket = new DatagramSocket(9090); //接受数据包 byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet);//阻塞接受 System.out.println(packet.getAddress().getHostAddress()); System.out.println(new String(packet.getData(),0,packet.getLength())); //关闭连接 socket.close(); } }
(二)、循环发送消息
接收方
package com.chat; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UdpReceiveDemo01 { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); while(true){ //准备接受包裹 byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); //阻塞时接收包裹 socket.receive(packet); //断开连接bye byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); System.out.println(receiveData); if(receiveData.equals("bye")){ break; } } socket.close(); } }
发送方
package com.chat; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class UdpSenderDemo01 { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8888); //准备数据:控制台读取System.in BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while(true){ String data = reader.readLine(); byte[] datas = data.getBytes(); DatagramPacket packet = new DatagramPacket(datas,0,datas.length, new InetSocketAddress("localhost",6666)); socket.send(packet); if(data.equals("bye")){ break; } } socket.close(); } }
启动顺序,先接收,后发送方。检查成功:在发送方输入字符串,查看接收方的消息
(三)、相互咨询
结合了多线程
谈话发送端
package com.chat; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; public class TalkSend implements Runnable { DatagramSocket socket = null; BufferedReader reader = null; private int fromPort; private String toIP; private int toPort; public TalkSend(int fromIP, String toIP, int toPort) { this.fromPort = fromIP; this.toIP = toIP; this.toPort = toPort; try{ socket = new DatagramSocket(fromPort); reader = new BufferedReader(new InputStreamReader(System.in)); }catch(Exception e){ e.printStackTrace(); } } @Override public void run() { while(true){ try{ String data = reader.readLine(); byte[] datas = data.getBytes(); DatagramPacket packet = new DatagramPacket(datas,0,datas.length, new InetSocketAddress(this.toIP,this.toPort)); socket.send(packet); if(data.equals("bye")){ break; } }catch (Exception e){ e.printStackTrace(); } } socket.close(); } }
谈话接收端
package com.chat; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class TalkReceive implements Runnable { DatagramSocket socket = null; private int port;//端口号 private String msfFrom; public TalkReceive(int port, String msfFrom) { this.port = port; this.msfFrom = msfFrom; try { socket = new DatagramSocket(port); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while(true){ try { //准备接受包裹 byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); //阻塞时接收包裹 socket.receive(packet); //断开连接bye byte[] data = packet.getData(); String receiveData = new String(data, 0, data.length); System.out.println(msfFrom+":"+receiveData); if(receiveData.equals("bye")){ break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
学生端
package com.chat; public class TalkSudent { public static void main(String[] args) { //开启两个线程 new Thread(new TalkSend(7777,"localhost",9999)).start(); new Thread(new TalkReceive(8888,"老师")).start(); } }
老师端
package com.chat; public class TalkTeaaher { public static void main(String[] args) { //两个进程,发送的端口 到达的端口 //接收时候的端口,从哪里来 new Thread(new TalkSend(5555,"localhost",8888)).start(); new Thread(new TalkReceive(9999,"学生")).start(); } }
结果运行图