【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

简介: 哈喽,大家好~我是你们的老朋友:保护小周ღ,本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘

 

image.gif编辑

哈喽,大家好~我是你们的老朋友: 保护小周ღ,本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘

image.gif编辑


Socket 套接字可以理解为是操作系统提供给程序员的一组用于网络编程的API (接口)——传输层的接口,传输层给应用层提供的一组 API,统称为 Socket API 。网络通信的底层逻辑都已经被操作系统封装好了,开发人员就可以根据接口开发实现网络通信。

Socket 套接字主要针对传输层协议分为如下三类:

    • 字节流套接字:使用传输层TCP协议
    • 数据报套接字:使用传输层UDP协议
    • 原始套接字:用于自定义传输层协议

    本篇博客主要讲述面向数据报的网络编程。


    一、Java基于UDP数据报套接字通信模型

    UDP 协议的特点:

      1. 面向无连接:传输数据之前,通信双方不依赖于建立连接,只需要知道谁发给谁即可。
      2. 不可靠传输:只负责发送,不关注数据是否传输成功,即使没发送成功啥也不干,也没有反馈
      3. 面向数据报:使用 UDP 数据报的形式传输,数据报可以理解为数据是一块一块的传输。image.gif编辑
      4. 有缓存区的概念:接收缓冲区,发送缓冲区:在进行网络数据通信时,用于存储待发送或已接收数据的缓冲区。
      5. 数据传输大小受限制:一个UDP 数据报最大占 64k, 1k = 1024字节
      6. 全双工通信:通信双方都可以同时进行信息交互

      总结:UDP 协议,具有面向无连接,面向数据报特点,即使通信双方没有建立连接,也会传输数据,并且一次性发送全部的数据报,一次性接受全部的数据报。

      Java 中基于UDP协议通信,主要使用 DatagramSocket 类来创建数据报套接字,并使用
      DatagramPacket 作为发送或接收的UDP数据报。


      针对一个客户端对服务器发出一次请求,服务器针对该请求给予响应流程如下:

      image.gif编辑在真实的网络环境中,一个服务器往往会给多个客户端提供响应。

      举个实际的例子根据以上流程图理解一下,张三老铁使用手机百度浏览器搜索 “美女图片”,此时前端页面就会将这条搜索记录 “美女图片” 拿到后台打包成UDP 数据报,以请求的形式发给百度服务器,百度服务器拿到请求后,解析数据报查看:哦~ 要美女啊,我这有很多,于是将“本地”存储的美女图片作为 UDP 数据报的形式响应给请求端,百度浏览器拿到百度服务器响应的数据后,通过解析,将图片展示在张三的手机界面上。


      二、UDP 数据报套接字编程

      2.1  DatagramSocket API

      DatagramSocket 是Socket 套接字基于UDP 协议来发送和接受数据报的类.

      Datagram : 数据报

      Socket : 说明这个对象是一个 Socket 对象

      Socket 对象相当于操作系统一个特殊的文件,这个文件并非对应对应的硬盘上的某个数据存储区域,而是对应到,网卡这个硬件!!!

      往 socket 对象中写数据,相当于通过网卡发送消息

      从 socket 对象中读数据,相当于通过网卡接收消息

      所以想要进行网络编程使得两个设备相互通信,就需要有 socket 文件这样的对象,借助这个 socket 文件对象来间接的操作网卡,操作系统基本设计思想:一切皆文件,为了简化系统内核的逻辑设计,socket 对象面向字节流读写


      image.gif编辑

      此处Socket 对象可以被客户端 / 服务端使用,服务器这边的 Socket 必须要关联一个具体的端口号,每个联网的设备在启动时或随机或指定都会绑定一个端口号,作为该应用程序的唯一标识,就相当于数据被你的设备接收,经解析需要知道这些数据需要交给那个应用程序处理。例如,qq 、微信没见过消息发串了的情况吧。

      客户端这边可以不需要手动指定,系统会自动随机分配,端口号的取值范围是 [0, 65535]。

      小于等于1024 的端口号,会提供给知名的服务器使用,不建议使用这一类。


      image.gif编辑

      socket 也是文件,用完了要关闭资源。


      2.2  DatagramPacket API

      DatagramPacket 类是用于基于UDP 协议的Socket 发送和接收的数据报。

      image.gif编辑

      只有两个参数的版本,不需要设计地址,通常用来接收消息。另一个多参数的版本需要显式的设置地址进去,通常要用来发送消息。


      image.gif编辑

      构造UDP 发送的数据报时,需要传入 socketAddress对象,这个对象可以使用 InetSocketAddress 来创建 。

      InetSocketAddress API 的构造方法:

      image.gif编辑


      三、基于UDP Socket 实现客户端,服务器程序

      分析客户端的程序的功能:

      1.发出请求(消息)

      2. 等待服务器响应(回应)

      3. 解析服务器的响应

      分析服务端的程序的功能:

      1. 尝试读取客户端的请求并解析

      2. 根据客户端的请求,统筹响应的数据

      3. 把响应返回到客户端


      3.1 服务端程序设计

      首先我们定义一个服务端的类:UdpEchoServer

      定义一个 Socket 对象文件,与网卡交互。

      //需要线定义一个 socket 对象//通过网络通信,必须要使用 socket 对象privateDatagramSocketsocket=null;

      image.gif

      利用 UdpEchoServer类 的构造方法为 socket 构造,并指定需要绑定的端口号

      publicUdpEchoServer(intserverPort) throwsSocketException {
      //构造 socket 的同时,指定要的关联/ 绑定的端口socket=newDatagramSocket(serverPort);
        }

      image.gif

      绑定一个端口,不一定能成功,如果某个端口已经被别的进程占用了,此时这里的绑定操作就会出错,同时一个主机上,一个端口,同一时刻,只能被一个进程绑定。所以这里会抛出异常。


      定义一个启动方法:start()

      方法内部采用循环的方式,每次循环,做三件事:

      1. 读取请求并解析,2. 根据请求计算响应,3. 把响应的结果写回客服端

      publicvoidstart() throwsIOException {
      System.out.println("服务器启动!");
      while (true) {
      // 每次循环,要做三件事情:// 1. 读取请求并解析// 构造接受请求的“空盒子”,指定盒子的大小 4096 字节DatagramPacketrequestPacket=newDatagramPacket(newbyte[4096], 4096);
      // 数据从网卡上来的socket.receive(requestPacket);// 获取客户端的请求、//为了方便处理这个请求,把二进制数据转换成 StringStringrequest=newString(requestPacket.getData(), 0, requestPacket.getLength());
      // 2. 根据请求计算响应 调用方法Stringresponse=process(request);
      /* 3. 把响应结果写回客服端根据response 字符串,构造一个 DatagramPacket和请求 packet 不同,此处构造响应的时候,需要指定这个包要发给谁 */DatagramPacketresponsePacket=newDatagramPacket(response.getBytes(), response.getBytes().length, requestPacket.getSocketAddress());
      // response.getBytes() 转换为 byte二进制流// requestPacket 是从客户端这里收来的,getSocketAddress 就会得到客户端的 IP 和 端口socket.send(responsePacket);// 响应// 可以保存以下日志Stringnow3=df.format(System.currentTimeMillis()); // 返回当前系统时间try(Writerwriter=newFileWriter("outPut.txt", true)) {
      writer.write(requestPacket.getAddress().toString() +requestPacket.getPort() +" "+now3+" req: "+request+" resp:  "+response+"\n");
                  }
      // 打印一下本次客户端与服务端的交互System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),
      requestPacket.getPort(), request, response);
              }
          }

      image.gif

      publicstaticvoidmain(String[] args) throwsIOException {
      UdpEchoServerudpEchoServer=newUdpEchoServer(9090);
      udpEchoServer.start();
          }

      image.gif

      2. 根据客户端的请求,统筹响应的数据,我们将第二步计算响应以函数的方式封装实现,参数 request 请求我们已经转换为字符串了,所以我们就可以依据请求做出对应的处理了,如果是需要搜索什么,就可以根据请求的内容将服务器的中存储的被搜索内容作为响应返回给客户端,如果是互相发消息,那就需要根据请求判断需要发给谁,此时需要双方约定在请求中添加接收方的IP 和 端口,这样才能找到接收方,作为服务器端来讲就需要使用多线程的思想,每一个客户端发来请求都会分配一个线程来处理。

      publicStringprocess(Stringrequest) { //这里直接将客户端的请求,作为响应返回return"服务器响应:"+request;
          }

      image.gif

      这个部分可以依据客户端的请求,进行对应的业务处理。


      3.2 客户端程序设计

      首先定义一个客户端的类:UdpEchoClient

      定义一个 Socket 对象文件,与网卡交互。

      定义 serverIP 的成员变量,用于存储服务器端的IP 地址

      定义 serverPort 的成员变量,用于存储服务器的端口号

      privateDatagramSocketsocket=null;
      privateStringserverIP=null; // IPprivateintserverPort=0; // 端口号 —— 代表进程的标识

      image.gif

      利用 UdpEchoClient 类 的构造方法为 socket 构造,并为成员方法关联服务器的 IP 地址和端口

      //客户端启动,需要知道服务器在哪儿!!publicUdpEchoClient(StringserverIP, intserverPort) throwsSocketException {
      //对于客户端来说,不需要显示关联端口// 不代表没有端口,而是系统自动分配了个空闲的端口socket=newDatagramSocket(); //获取随机端口号this.serverIP=serverIP;
      this.serverPort=serverPort;
          }

      image.gif

      定义一个启动方法:start()

      方法内部采用循环的方式,每次循环,做4件事:

      1. 从控制台获取用户输入的信息

      2. 将获取的信息构造成 UDP 数据报,并向服务器发送请求

      3. 客户端尝试获取读取服务器返回的响应

      4. 将获取的的响应根据业务需求做进一步的处理

      publicvoidstart() throwsIOException {
      // 通过这个客户端可以多次和服务器进行交互System.out.println("客户端启动!");
      Scannerin=newScanner(System.in);
      while (true) {
      //1.先从控制台,读取一个字符串过来//先打印一个提示符,提示用户要输入内容System.out.print("->");
      Stringrequest=in.next();
      //2. 把字符串构造成 UDP packet, 并进行发送DatagramPacketrequestPacket=newDatagramPacket(
      request.getBytes(),
      request.getBytes().length,
      //----如果参数为null,获得的是本机的IP地址InetAddress.getByName(serverIP),// 确定主机的 IP 地址----在给定主机名的情况下确定主机的IP地址serverPort);
      socket.send(requestPacket); //响应//3. 客户端尝试读取服务器返回的响应DatagramPacketresponsePacket=newDatagramPacket(newbyte[4096], 4096);
      socket.receive(responsePacket);
      //4. 把响应的数据转换成 String 显示出来,利用 String 的构造方法转换Stringresponse=newString(responsePacket.getData(), 0, responsePacket.getLength());
      System.out.printf("req: %s, resp: %s\n", request, response);
              }
          }

      image.gif

      publicstaticvoidmain(String[] args) throwsIOException {
      UdpEchoClientudpEchoClient=newUdpEchoClient("127.0.0.1",9090);
      udpEchoClient.start(); // 启动客户端    }

      image.gif


      3.3 总结:

      以上客户端服务器代码使用了 Socket “ 文件流”, 但是没有调用 close() 方法释放资源,是因为文件流会随着进程的关闭而关闭,但是在实际开发中一定要记得随手关闭哦~

      启动客户端和服务器展示效果:

      image.gif编辑

      image.gif编辑

      image.gif编辑

      以上操作流程执行图。image.gif编辑

      一定是先启动服务器,再启动客户端,

      UDP(User Datagram Protocol)是一个无连接的传输层协议,它不保证数据包可靠传输。UDP比TCP更快,而且在对网络延迟要求较低、对数据准确性要求不高的情况下使用。本文将讨论基于UDP Socket的客户端服务器开发总结。

      UDP Socket

      Socket是一种用于在计算机之间进行通信的 API(应用程序接口)。UDP Socket是基于UDP协议进行通信的套接字,它提供了一种快速发送和接收数据包的方法,但是与TCP不同,它不会重复数据或者检查是否有缺失的数据包。

      编写UDP客户端的基本步骤如下:

        1. 创建一个UDP socket。
        2. 将要发送的数据打包到UDP数据包中。
        3. 使用UDP socket发送数据包到特定的IP地址和端口号。

        编写UDP服务器的基本步骤如下:

          1. 创建一个UDP socket并监听特定的端口号。
          2. 接收客户端发送的数据包。
          3. 处理数据包,然后将响应打包到另一个UDP数据包中。
          4. 使用UDP socket向客户端发送响应数据包。


          在使用UDP Socket进行客户端和服务器开发时,需要注意以下几点:

            • UDP不会保证数据包的可靠传输,因此需要在应用程序中处理数据包的丢失或者损坏情况。
            • 由于UDP没有连接状态,因此可以同时与多个客户端通信。
            • 在UDP通信中,需要指定目标地址和端口号。

            到这里,网络编程中的基于UDP-Socket 实现客户端,服务器通信念博主已经分享完了,希望对大家有所帮助,如有不妥之处欢迎批评指正。

            image.gif编辑

            本期收录于博主的专栏——JavaEE,适用于编程初学者,感兴趣的朋友们可以订阅,查看其它“JavaEE基础知识”。

            下期预告:TCP 协议

            感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★*

            遇见你,所有的星星都落在我的头上……

            相关文章
            |
            6月前
            |
            JSON 移动开发 网络协议
            Java网络编程:Socket通信与HTTP客户端
            本文全面讲解Java网络编程,涵盖TCP与UDP协议区别、Socket编程、HTTP客户端开发及实战案例,助你掌握实时通信、文件传输、聊天应用等场景,附性能优化与面试高频问题解析。
            |
            4月前
            |
            JSON 网络协议 安全
            【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
            几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
            269 1
            |
            4月前
            |
            JSON 网络协议 安全
            【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
            几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
            260 1
            |
            4月前
            |
            机器学习/深度学习 分布式计算 Java
            Java与图神经网络:构建企业级知识图谱与智能推理系统
            图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
            475 0
            |
            9月前
            |
            人工智能 Java API
            MCP客户端调用看这一篇就够了(Java版)
            本文详细介绍了MCP(Model Context Protocol)客户端的开发方法,包括在没有MCP时的痛点、MCP的作用以及如何通过Spring-AI框架和原生SDK调用MCP服务。文章首先分析了MCP协议的必要性,接着分别讲解了Spring-AI框架和自研SDK的使用方式,涵盖配置LLM接口、工具注入、动态封装工具等步骤,并提供了代码示例。此外,还记录了开发过程中遇到的问题及解决办法,如版本冲突、服务连接超时等。最后,文章探讨了框架与原生SDK的选择,认为框架适合快速构建应用,而原生SDK更适合平台级开发,强调了两者结合使用的价值。
            12370 33
            MCP客户端调用看这一篇就够了(Java版)
            |
            9月前
            |
            存储 网络协议 Java
            Java获取客户端IP问题:返回127.0.0.1
            总结:要解决Java获取客户端IP返回127.0.0.1的问题,首先要找出原因,再采取合适的解决方案。请参考上述方案来改进代码,确保在各种网络环境下都能正确获取客户端IP地址。希望本文对您有所帮助。
            599 25
            |
            4月前
            |
            弹性计算 运维 安全
            阿里云轻量应用服务器与云服务器ECS啥区别?新手帮助教程
            阿里云轻量应用服务器适合个人开发者搭建博客、测试环境等低流量场景,操作简单、成本低;ECS适用于企业级高负载业务,功能强大、灵活可扩展。二者在性能、网络、镜像及运维管理上差异显著,用户应根据实际需求选择。
            385 10
            |
            4月前
            |
            运维 安全 Ubuntu
            阿里云渠道商:服务器操作系统怎么选?
            阿里云提供丰富操作系统镜像,涵盖Windows与主流Linux发行版。选型需综合技术兼容性、运维成本、安全稳定等因素。推荐Alibaba Cloud Linux、Ubuntu等用于Web与容器场景,Windows Server支撑.NET应用。建议优先选用LTS版本并进行测试验证,通过标准化镜像管理提升部署效率与一致性。
            |
            4月前
            |
            弹性计算 ice
            阿里云4核8g服务器多少钱一年?1个月和1小时价格,省钱购买方法分享
            阿里云4核8G服务器价格因实例类型而异,经济型e实例约159元/月,计算型c9i约371元/月,按小时计费最低0.45元。实际购买享折扣,1年最高可省至1578元,附主流ECS实例及CPU型号参考。
            548 8
            |
            4月前
            |
            存储 监控 安全
            阿里云渠道商:云服务器价格有什么变动?
            阿里云带宽与存储费用呈基础资源降价、增值服务差异化趋势。企业应结合业务特点,通过阶梯计价、智能分层、弹性带宽等策略优化成本,借助云监控与预算预警机制,实现高效、可控的云资源管理。