Java网络编程

    xiaoxiao2021-12-12  2

    UDP协议是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket,但在两个Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据报的对象。Java提供了DatagramSocket对象作为基于UDP协议的Socket,使用DatagramPacket代表DatagramSocket发送、接收的数据包。

    UDP协议是面向非连接的协议,没有建立连接的过程,因此它的通信效率很高;也正是因为如此,它的可靠性不如TCP协议。

    UDP协议和TCP协议的简单比较:

    TCP协议:可靠,传输大小无限制,但是需要连接建立时间,差错控制开销大。 UDP协议:不可靠,差错控制开销小,传输大小限制在64KB以下,不需要建立连接。


    DatagramSocket与DatagramPacket

    Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket唯一作用就是接收和发送数据报。Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。

    DatagramSocket构造器DatagramSocetk()创建一个DatagramSocket实例,并将对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。DatagramSocket(int port)创建一个DataGramSocket实例,并将该对象绑定到本机默认IP地址、指定端口DatagramSocket(int port,InetAddress Iaddr)创建一个DatagramSocket实例,并将对象绑定到指定IP地址、指定端口

    得到DatagramSocket实例之后,可以通过以下方法来接收和发送数据:

    DatagramSocket方法receive(DatagramPacket p)从该DatagramSocket中接收数据报send(DatagramPacket p)以该DatagramSocket对象向外发送数据报

    DatagramPacket构造器及方法

    DatagramPacket的构造器DatagramPacket(byte[] buf,int length)以一个空数组来创建DatagramPacket对象,该对象的作用是接收DatagramSocket中的数据DatagramPacket(byte[] buf,int length,InetAddress addr,int port)以一个包含数据的数组来创建DatagramPacket对象,创建该DatagramPacket对象时还指定了IP地址和端口——这就是决定了该数据报的目的地DatagramPacket(byte[] buf,int offset,int length)以一个空数组来创建DatagramPacket对象,并指定接收到的数据放入buf数组中时从offset开始,最多放length个字节DatagramPacket(byte[] buf,int offset,int length,InetAddress addr,int port)创建一个用于发送的DatagramPacket对象,指定发送buf数组中从offset开始,总共length个字节

    在接收数据之前,应该采用DatagramPacket的第一个或第三个构造器生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用DatagramSocket的receive()方法等待数据报的到来,receive()将一直等待(该方法会阻塞调用该方法的线程),直到受到一个数据报为止。

    //创建一个接收数据的DatagramPacket对象 DatagramPacket packet = new DatagramPacket(buf, 256); //接收数据报 socket.receive(packet);

    在发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的send()方法实现的,send()方法根据数据包的目的地址来寻径以传送数据报。

    //创建一个发送数据的DatagramPacket对象 DatagramPacket packet = new Datagrampacket(buf, length, address, port); //发送数据报 socket.send(packet);

    当服务器端接收到一个DatagramPacket对象后,如果想向该数据包的发送者“反馈”一些信息,但由于UDP协议是面向非连接的,所以接收者并不知道每个数据报由谁发送过来,但程序可以调用DatagramPacket的如下三个方法来获取发送者的IP地址和端口。

    方法InetAddress getAddress()当程序准备发送此数据报时,该方法返回此数据报的目标机器的IP地址;当程序接收到一个数据报时,该方法返回该数据报的发送主机的IP地址int getPort()当程序准备发送此数据报时,该方法返回此数据报的目标机器的端口;当程序刚接收到一个数据报时,该方法返回该数据报的发送主机的端口SocketAddress getSocketAddress()当程序准备发送此数据报时该方法返回此数据报的目标SocketAddress;当程序刚接收到一个数据报时,该方法返回该数据报的发送主机的SocketAddress

    实例代码:

    public class UDPServer { public static final int PORT = 30000; //定义每个数据报的大小最大为4KB private static final int DATA_LEN = 4096; //定义接收网络数据的字节数组 byte[] inBuff = new byte[DATA_LEN]; //以指定字节数组创建准备接收数据的DatagramPacket对象 private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length); //定义一个用于发送的DatagramPacket对象 private DatagramPacket outPacket; //定义一个字符串数组,服务器端发送该数组的元素 String[] books = new String[]{"qqq", "www", "eee", "rrr"}; public void init() throws IOException{ try( //创建DatagramSocket对象 DatagramSocket socket = new DatagramSocket(PORT)){ //采用循环接收数据 for(int i = 0; i < 1000; i++){ //读取Socket中的数据,读到的数据放入inPacket封装的数组里 socket.receive(inPacket); //判断inPacket.getData()和inBuff是否是同一个数组 System.out.println(inBuff == inPacket.getData()); //将接收到的内容转换为字符串后输出 System.out.println(new String(inBuff, 0, inPacket.getLength())); //从字符串数组中取出一个元素作为发送数据 byte[] sendData = books[i % 4].getBytes(); //以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的源SocketAddress作为 //目标SocketAddress创建DatagramPacket outPacket = new DatagramPacket(sendData, sendData.length, inPacket.getSocketAddress()); //发送数据 socket.send(outPacket); } } } public static void main(String[] args) throws IOException{ new UDPServer().init(); } } public class UDPClient { //定义发送数据报的目的地 public static final int DEST_PORT = 30000; public static final String DEST_IP = "127.0.0.1"; //定义每个数据报的大小最大为4KB private static final int DATA_LEN = 4096; //定义接收网络数据的字节数组 byte[] inBuff = new byte[DATA_LEN]; //以指定的字节数组创建准备接收数据的DatagramPacket对象 private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length); //定义一个用于发送的DatagramPacket对象 private DatagramPacket outPacket = null; public void init() throws IOException{ try( //创建一个客户端DatagramSocket,使用随机端口 DatagramSocket socket = new DatagramSocket()){ //初始化发送时用的DatagramSocket,它包含一个长度为0的字节数组 outPacket = new DatagramPacket(new byte[0], 0, InetAddress.getByName(DEST_IP), DEST_PORT); //创建键盘输入流 Scanner scan = new Scanner(System.in); //不断地读取键盘输入 while(scan.hasNextLine()){ //将键盘输入的一行字符串转换为字节数组 byte[] buff = scan.nextLine().getBytes(); //设置发送用的DatagramPacket中的字节数据 outPacket.setData(buff); //发送数据报 socket.send(outPacket); //读取Socket中的数据,读取到的数据放在inPacket所封装的字节数组中 socket.receive(inPacket); System.out.println(new String(inBuff, 0, inPacket.getLength())); } } } public static void main(String[] args) throws IOException{ new UDPClient().init(); } }
    转载请注明原文地址: https://ju.6miu.com/read-900321.html

    最新回复(0)