Socket套接字之UDP网络编程 单向 双向 异常处理 基于UDP实现两人正常通信

Socket套接字之UDP网络编程 单向 双向 异常处理

套接字(Socket)

  • 用来描述IP地址和端口,是通信链的句柄,应用程序通过Socket向网络发送请求或者应答网络请求
  • 是支持TCP/IP协议的网络通信的基本操作单元,
  • 是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象,内含五种信息:连接使用的协议,本机IP即进程接口PORT,远程主机IP及进程接口PORT。
  • 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。
  • 从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。

Socket示意图

Socket通讯模型

UDP

UDP是基于IP的简单协议,不可靠的协议。没有流控制,没有应答确认机制,也不能解决丢包、重发、错序问题;但也因此更加的简单,轻量化。它除了给应用程序发送数据包功能并允许它们在所需的层次上架构自己的协议之外,几乎没有做什么特别的事情。发送方和接收方的地址是平等的。

发送方:DatagramSocket 发送:数据包 DatagramPacket
接收方:DatagramSocket 接收:数据包 DatagramPacket

DatagramPacket构造器及方法:

构造器

  • DatagramPacket(byte[] buf, int length)

构造数据报包,用来接收长度为 length 的数据包

  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)

构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号

方法

  • InetAddress getAddress()

    • 返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
  • byte[] getData()

    • 返回数据缓冲区。
  • int getLength()

  • 返回将要发送或接收到的数据的长度。

  • int getPort()

    • 返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。

接下来是UDP通信实例,暂不处理异常,直接抛出甩锅,运行时先开启接收方再开启发送方,否则会丢包

单向通信

接收方

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Receive {
    public static void main(String[] args) throws IOException {
        System.out.println("老师上线");
        //1.创建套接字:指定接收方的端口
        DatagramSocket ds = new DatagramSocket(8888);

        //2.有一个空的数据包,打算用来接收对方传过来的数据包:
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b,b.length);

        //3.接收对方的数据包,然后放入我们的dp数据包中填充
        ds.receive(dp);//接收完以后 dp中便有填充好的内容

        //4.取出数据:
        byte[] data = dp.getData();
        String s = new String(data,0,dp.getLength());//dp.getLength()数组包中的有效长度
        System.out.println("学生对我说:"+s);

        //5.关闭资源:
        ds.close();
    }
}

发送方

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Send {
    public static void main(String[] args) throws IOException {
        System.out.println("学生上线");
        //1.准备套接字: 指定发送方的端口号
        DatagramSocket ds = new DatagramSocket(8889);

        //2.准备数据包
        String str = "你好";
        byte[] bytes = str.getBytes();
        // DatagramPacket(byte[] 分组数据。 int 包长度。 InetAddress 目的地址。 int 目的端口号)
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),8888);

        //发送:
        ds.send(dp);
        System.out.println("已发送");
        //关闭资源
        ds.close();
    }
}
通信过程
Send:
学生上线
已发送

Receive:
老师上线
学生对我说:你好

双向通信

接收方

public class Receive {
    public static void main(String[] args) throws IOException {
        System.out.println("老师上线");
        //1.创建套接字:指定接收方的端口
        DatagramSocket ds = new DatagramSocket(9999);

        //2.有一个空的数据包,打算用来接收  对方传过来的数据包:
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b,b.length);

        //3.接收对方的数据包,然后放入我们的dp数据包中填充
        ds.receive(dp);//接收完以后 dp里面就填充好内容了

        //4.取出数据:
        byte[] data = dp.getData();
        String s = new String(data,0,dp.getLength());
        System.out.println("学生说:"+s);
        //老师进行回复:
        Scanner sc = new Scanner(System.in);
        System.out.print("我:");
        String str = sc.next();
        byte[] bytes = str.getBytes();
        //封装数据,并且指定学生的IP和端口号
        DatagramPacket dp2 = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),8888);
        //发送:
        ds.send(dp2);

        //5.关闭资源:
        ds.close();
    }
}

发送方

public class Send {
    public static void main(String[] args) throws IOException {
        System.out.println("学生上线");
        //1.准备套接字: 指定发送方的端口号
        DatagramSocket ds = new DatagramSocket(8888);
        //2.准备数据包
        Scanner sc = new Scanner(System.in);
        System.out.print("我:");
        String str = sc.next();
        byte[] bytes = str.getBytes();

        // DatagramPacket(byte[] 分组数据。 int 包长度。 InetAddress 目的地址。 int 目的端口号)
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
        //发送:
        ds.send(dp);
        //接收老师发送回来的信息:
        byte[] b = new byte[1024];
        DatagramPacket dp2 = new DatagramPacket(b,b.length);
        ds.receive(dp2);//接收完以后 dp2里面就填充好内容了
        //取出数据:
        byte[] data = dp2.getData();
        String s = new String(data,0,dp2.getLength());//dp.getLength()数组包中的有效长度
        System.out.println("老师说:"+s);
        //关闭资源
        ds.close();
    }
}
通信过程
学生上线
我:我是Fyz
老师说:我是Teacher

老师上线
学生说:我是Fyz
我:我是Teacher Wang

异常处理

以双向通信为例

try-catch-fianlly

接收方

public class Receive {
    public static void main(String[] args){
        System.out.println("老师上线");
        //1.创建套接字:指定接收方的端口
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(9999);
            //2.有一个空的数据包,打算用来接收  对方传过来的数据包:
            byte[] b = new byte[1024];
            DatagramPacket dp = new DatagramPacket(b,b.length);
            //3.接收对方的数据包,然后放入我们的dp数据包中填充
            ds.receive(dp);//接收完以后 dp里面就填充好内容了
            //4.取出数据:
            byte[] data = dp.getData();
            String s = new String(data,0,dp.getLength());
            System.out.println("学生说:"+s);
            //老师进行回复:
            Scanner sc = new Scanner(System.in);
            System.out.print("我:");
            String str = sc.next();
            byte[] bytes = str.getBytes();
            //封装数据,并且指定学生的IP和端口号
            DatagramPacket dp2 = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),8888);
            //发送:
            ds.send(dp2);
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{//5.关闭资源:
            assert ds != null;
            ds.close();
        }
    }
}

发送方

public class Send {
    public static void main(String[] args){
        System.out.println("学生上线");
        //1.准备套接字: 指定发送方的端口号
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(8888);
            //2.准备数据包
            Scanner sc = new Scanner(System.in);
            System.out.print("我:");
            String str = sc.next();
            byte[] bytes = str.getBytes();

// DatagramPacket(byte[] 分组数据。 int 包长度。 InetAddress 目的地址。 int 目的端口号)
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
            //发送:
            ds.send(dp);
            //接收老师发送回来的信息:
            byte[] b = new byte[1024];
            DatagramPacket dp2 = new DatagramPacket(b,b.length);
            ds.receive(dp2);//接收完以后 dp2里面就填充好内容了
            //取出数据:
            byte[] data = dp2.getData();
            String s = new String(data,0,dp2.getLength());//dp.getLength()数组包中的有效长度
            System.out.println("老师说:"+s);
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{ //关闭资源
            assert ds != null;
            ds.close();
        }
    }
}

try-with-resource

接收方

public class Receive {
    public static void main(String[] args){
        System.out.println("老师上线");
        //1.创建套接字:指定接收方的端口
        try (DatagramSocket ds = new DatagramSocket(9999);){
            //2.有一个空的数据包,打算用来接收  对方传过来的数据包:
            byte[] b = new byte[1024];
            DatagramPacket dp = new DatagramPacket(b,b.length);
            //3.接收对方的数据包,然后放入我们的dp数据包中填充
            ds.receive(dp);//接收完以后 dp里面就填充好内容了
            //4.取出数据:
            byte[] data = dp.getData();
            String s = new String(data,0,dp.getLength());
            System.out.println("学生说:"+s);
            //老师进行回复:
            Scanner sc = new Scanner(System.in);
            System.out.print("我:");
            String str = sc.next();
            byte[] bytes = str.getBytes();
            //封装数据,并且指定学生的IP和端口号
            DatagramPacket dp2 = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),8888);
            //发送:
            ds.send(dp2);
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

发送方

public class Send {
    public static void main(String[] args){
        System.out.println("学生上线");
        //1.准备套接字: 指定发送方的端口号
        try (DatagramSocket ds = new DatagramSocket(8888);){
            //2.准备数据包
            Scanner sc = new Scanner(System.in);
            System.out.print("我:");
            String str = sc.next();
            byte[] bytes = str.getBytes();

            // DatagramPacket(byte[] 分组数据。 int 包长度。 InetAddress 目的地址。 int 目的端口号)
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
            //发送:
            ds.send(dp);
            //接收老师发送回来的信息:
            byte[] b = new byte[1024];
            DatagramPacket dp2 = new DatagramPacket(b,b.length);
            ds.receive(dp2);//接收完以后 dp2里面就填充好内容了
            //取出数据:
            byte[] data = dp2.getData();
            String s = new String(data,0,dp2.getLength());//dp.getLength()数组包中的有效长度
            System.out.println("老师说:"+s);
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

正常通信(一直连接)

接收方

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class Receive {
    public static void main(String[] args){
        System.out.println("老师上线");
        //1.创建套接字:指定接收方的端口
        try (DatagramSocket ds = new DatagramSocket(9999);){
           while(true){
               //2.有一个空的数据包,打算用来接收  对方传过来的数据包:
               byte[] b = new byte[1024];
               DatagramPacket dp = new DatagramPacket(b,b.length);
               //3.接收对方的数据包,然后放入我们的dp数据包中填充
               ds.receive(dp);//接收完以后 dp里面就填充好内容了
               //4.取出数据:
               byte[] data = dp.getData();
               String s = new String(data,0,dp.getLength());
               System.out.println("学生说:"+s);
               if (s.equals("再见")){
                   System.out.println("学生已下线,聊天终止");
                   break;
               }
               //老师进行回复:
               Scanner sc = new Scanner(System.in);
               System.out.print("我:");
               String str = sc.nextLine();
               byte[] bytes = str.getBytes();
               //封装数据,并且指定学生的IP和端口号
               DatagramPacket dp2 = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),8888);
               //发送:
               ds.send(dp2);
           }
        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

发送方

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class Send {
    public static void main(String[] args){
        System.out.println("学生上线");
        //1.准备套接字: 指定发送方的端口号
        try (DatagramSocket ds = new DatagramSocket(8888);){
            while(true){
                //2.准备数据包
                Scanner sc = new Scanner(System.in);
                System.out.print("我:");
                String str = sc.nextLine();
                byte[] bytes = str.getBytes();
                // DatagramPacket(byte[] 分组数据。 int 包长度。 InetAddress 目的地址。 int 目的端口号)
                DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("localhost"),9999);
                //发送:
                ds.send(dp);
                if (str.equals("再见")){
                    System.out.println("你已下线");
                    break;
                }
                //接收老师发送回来的信息:
                byte[] b = new byte[1024];
                DatagramPacket dp2 = new DatagramPacket(b,b.length);
                ds.receive(dp2);//接收完以后 dp2里面就填充好内容了
                //取出数据:
                byte[] data = dp2.getData();
                String s = new String(data,0,dp2.getLength());//dp.getLength()数组包中的有效长度
                System.out.println("老师说:"+s);
            }

        } catch (SocketException | UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
通讯实例
 Send方Receive方
上线 学生上线 老师上线
  Hello, Teacher Wang  
    Hello, Fyz
  I wonde what about the examination paper on C++  
    This got five more in the final exam papers
  再见  
下线 你已下线 学生已下线,聊天终止
posted @ 2021-08-12 13:21  SKPrimin  阅读(119)  评论(0编辑  收藏  举报