• Socket数据报套接字


    概念

    Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元.
    基于Socket套接字的网络程序开发就是网络编程.

    数据报套接字

    使用的是UDP(User Datagram Protocol)协议,传输层协议.

    • 无连接
    • 不可靠传输
    • 面向数据报
    • 全双工

    对于UDP协议来说,具有无连接,面向数据报的特征,每次都是没有建立连接,并且一次性发送全部数据报,并一次性接收全部数据报.
    java使用UDP协议通信,基于DatagramSocket类创建数据报套接字,并使用DatagramPacket作为发送或接收的UDP数据报.

    DatagramSocket

    DatagramSocket是UDP Socket,用于发送和接收UDP数据报.

    DatagramSocket构造方法:

    方法签名方法说明
    DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
    DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到指定端口(一般用于服务器端)

    DatagramSocket方法:

    方法签名方法说明
    void receive(DatagramSocket p)就收套接字数据报,没有则会阻塞等待
    void send(DatagramSocket p)发送套接字数据报
    void close()关闭数据报套接字

    DatagramPacket

    DatagramPacket是UDP Socket发送和接受的数据报

    DatagramPacket构造方法:

    方法签名方法说明
    DatagramPacket(byte[] buf, int length)这是接收数据报,接收的数据保存在byte数组中,指定接收长度
    DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)这是发送数据报,发送的数据时字节数组,从0到指定长度,address指定目的主机的IP和端口号

    DatagramPacket方法:

    方法签名方法说明
    InetAddress getAddress()从接受的数据报中,获取发送端主机IP地址.或者从发送的数据报中,获取接收端主机的IP地址
    int getPort()从接受的数据报中,获取发送端主机的端口号.或者从发送的数据报中,获取接收端主机的端口号
    byte[] getData()获取数据报中的数据

    InetSocketAddress

    InetSocketAddress(SocketAddress的子类) 构造方法:

    方法签名方法说明
    InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

    下面写一个回显服务器案例供参考:

    // 服务器
    public class UdpEchoServer {
        private DatagramSocket socket = null;
        public UdpEchoServer(int port) throws SocketException {
            // 根据端口号构造, 端口号被占用的时候,会报错
            socket = new DatagramSocket(port);
        }
    
        public void start() throws IOException {
            System.out.println("服务器启动");
            while (true) {
                // 反复的,长期的反应客户端的请求处理的逻辑
                // 1. 读取请求,并解析。
                DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
                socket.receive(requestPacket);
                // 后续客户端必须发送文本文件,才能这样转字符串
                String request = new String(requestPacket.getData(),0, requestPacket.getLength());
                // 2. 根据请求,计算相应
                String response = process(request);
                // 3. 把响应返回给客户端
                DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,
                        requestPacket.getSocketAddress());
                socket.send(responsePacket);
                System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),requestPacket.getPort(),
                        request,response);
            }
        }
    
        private String process(String request) {
            return request;
        }
    
        public static void main(String[] args) throws IOException {
            UdpEchoServer server = new UdpEchoServer(999);
            server.start();
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    相信仔细看完的小伙伴注意到了,socket对象并没有调用close来关闭,因为此时整个程序
    只有一个socket,这个对象的生命周期非常长,是跟随整个程序的.
    socket对象->系统中的socket文件->文件描述符
    进程结束,就把pcb回收了,文件描述符也随之销毁了.
    但是如果有多个socket对象,需要频繁创建释放,一定要去进行close操作.

    // 客户端
    public class UDPEchoClient {
        private DatagramSocket socket = null;
    
        private String serverIp;
        private int serverPort;
    
        public UDPEchoClient(String ip, int port) throws SocketException {
            this.serverIp = ip;
            this.serverPort = port;
            // 随机端口号
            socket = new DatagramSocket();
        }
    
        // 让客户端反复地读取控制台内容,把内容构造成UDP请求,发给服务器
        public void start() throws IOException {
            Scanner scanner = new Scanner(System.in);
            System.out.println("客户端启动");
            while (true) {
                // 1.从控制台输入
                System.out.println("-> ");
                String request = scanner.nextLine();
                // 2.构造请求对象,发给服务器
                // 使用InetAddress的静态方法,getByName来进行构造(工厂模式)
                // InetAddress.getByName(serverIp),serverPort): 要发送的ip和端口
                DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),0,request.getBytes().length,
                        InetAddress.getByName(serverIp),serverPort);
                socket.send(requestPacket);
                // 3.客户端读取响应
                DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
                socket.receive(responsePacket);
                String response = new String(responsePacket.getData(),0, responsePacket.getLength());
                // 4. 显示到屏幕上
                System.out.println(response);
            }
        }
    
        public static void main(String[] args) throws IOException {
        	// 端口号和服务器端一致
            UDPEchoClient client = new UDPEchoClient("127.0.0.1", 999);
            client.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    小结

    本次总结了UDP套接字数据报的相关内容,TCP套接字放到下一章博客中.
    希望有收获的小伙伴多多支持.

  • 相关阅读:
    MongoDB之完整入门知识(集合操作、文档基本CRUD操作、文档分页查询、索引等相关命令)
    Hessian协议详解
    【漏洞分析】Li.Fi攻击事件分析:缺乏关键参数检查的钻石协议
    Maven - no main manifest attribute(SpringBoot 多模块)
    Go网络通信
    计算机视觉与深度学习实战,Python工具,深度学习的视觉场景识别
    苹果电脑mac系统运行卡顿 反应慢怎么办?
    黑马微服务课程2
    Redis技术总结
    房产销售数据分析与可视化的设计与实现
  • 原文地址:https://blog.csdn.net/lhs006/article/details/138197813