当前位置: 首页 > news >正文

UDP Socket API 的讲解,以及回显服务器客户端的实现

文章目录

    • UDP
      • DatagramSocktet API
      • DatagramPacket API
    • UDP 客户端服务器实现

UDP

先来认识一下 UDP 的 socket api,两个核心的类:DatagramSocket、DatagramPacket.

DatagramSocktet API

是一个 socket 对象。

什么是 socket?

操作系统,使用文件这样的概念,来管理一些软硬件资源。网卡,操作系统也是使用 文件 的方式来管理网卡的。表示网卡的这类文件,称为 Socket 文件。Java 中的 socket 对象,就对应 系统里的 socket 文件。

因此,想要进行网络通信,必须得先有 socket 对象。

DatagramSocket构造方法:

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

DatagramSocket() 在客户端这边使用,客户端使用哪个端口,是系统自动分配的。

一个客户端的主机,上面运行的程序很多,天知道你手动指定的端口是不是被别的程序占用了。因此,让系统自动分配一个端口是更明智的选择.

DatagramSocket(int port) 在服务器这边使用,服务器使用哪个端口,是手动指定的。

对于服务器来说,需要有一个固定的端口号,方便其他客户端找到。

DatagramSocket 方法:

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket API

表示了一个 UDP 发送和接收的数据报。

代表了系统中设定的 UDP 数据报的二进制结构。

DatagramPacket 构造方法:

方法签名说明方法
DatagramPacket(byte[] buf, int length)构造一个 DatagramPacket 用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数 length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)构造一个 DatagramPacket 用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

DatagramPacket 方法:

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

UDP 客户端服务器实现

接下来手动写 UDP 客户端服务器

实现一个最简单的回显服务器 (Echo Server).

回显服务器:顾名思义,就是客户端发啥,服务器就返回啥。

我们知道,一个服务器可以供多个客户端同时使用,因此我们最先想到的是利用多线程来实现 UDP.
但事实上 UDP 服务器不需要多线程,是因为UDP是无连接的,每个数据包都是独立的,服务器只需要监听一个端口,接收数据包并处理即可。

核心思路

  1. 服务器:
    • 接收客户端发送过来是请求 ( 收到的请求是一个 DatagramPacket 类 ),并解析出请求内容 ( 转换成 String 类)。
    • 根据请求做出响应
    • 把响应返回给客户端
  2. 客户端
    • 从控制台读取用户输入的内容.
    • 构造请求对象,并发给服务器.
    • 接收服务器给出的响应,并解析出响应内容.
    • 将响应内容打印出来.
  3. 客户端服务器相互关联:通过 ip 和 端口号.
    • ip:每个服务器都有自己的 ip 地址,客户端需要通过 ip 找到服务器。(127.0.0.1 就表示自己的电脑)
    • 端口号:每个服务器有很多个端口,端口号就是用于客户端到底是访问服务器的哪个端口。

实现 UDP 会用到的方法:

getSocketAddress() :就是 getAddress() 和 getPort() 的结合体. [address:port]

InetAddress.getByName(“主机名”):如果传入的是主机名,则该方法会尝试解析该主机名,如果解析成功,则返回对应的 IP 地址;如果解析失败,则抛出 UnknownHostException 异常.

getData():获取数据报中的数据.

客户端代码:

import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp ;private int serverPort;public UdpEchoClient(String ip, int port) throws SocketException {serverIp = ip;serverPort = port;// 这个 new 操作,就不再指定端口了,让系统自动分配一个空闲端口socket = new DatagramSocket();}public void start () throws IOException {Scanner scanner  = new Scanner(System.in);System.out.println("客户端启动!");while (true) {// 1. 从控制台读取用户输入的内容System.out.print("->");String request = scanner.nextLine();// 2. 构造请求对象,并发给服务器DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 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",9090);client.start();}
}/*客户端启动!->hellohello
*/

服务器代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;//回显服务器
//客户端发的请求是啥,服务器返回的响应就是啥
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(), response.getBytes().length, requestPacket.getSocketAddress());socket.send(responsePacket);//记录日记,方便观察程序执行效果System.out.printf("[%s:%d] req: %s , resp: %s\n", responsePacket.getAddress().toString(), responsePacket.getPort(),request, response);}}//根据请求计算响应,由于是回显程序,响应内容和请求完全一样private String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);    //设定服务器的端口号为 9090server.start();}
}/*服务器启动![/127.0.0.1:54015] req: hello , resp: hello
*/

问题1:我电脑上的 udp 服务器,别人可以访问吗??

答:不可以,因为我当前的电脑上没有 “外网IP”。解决办法就是买一个有外网的云服务器 😆

问题2:socket 对象用完后需要关闭吗??

答:需要,我们要知道为什么要关闭 socket 对象。最主要的就是释放系统中的 socket 文件,从而释放文件描述符

但是上述代码中我们为什么没去关闭 socket 对象呢?

因为对于咱们这个服务器来说,DatagramSocket 不关闭,问题不大。整个程序中只有一个 socket 对象,不是频繁创建的,生命周期是跟随整个进程的。但是如果是有多个 socket 对象, 且 socket 对象生命周期更短需要频繁创建释放。一定要记得去 close 。

http://www.lryc.cn/news/254660.html

相关文章:

  • 数据结构与算法-D7栈实现及应用
  • 蓝桥杯真题:分巧克力(二分法)-Java版
  • c++面试题
  • 高精度加法,减法,乘法,除法(上)(C语言)
  • C++新经典模板与泛型编程:SFINAE特性的信息萃取
  • java单人聊天
  • nodejs环境安装
  • R语言进行正态分布检验
  • 什么是SPA(Single Page Application)?它的优点和缺点是什么?
  • 由于找不到xinput1_3.dll,无法继续执行代码的多种解决方法指南,xinput1_3.dll文件修复
  • Vue---Echarts
  • uni-app实现返回刷新上一页
  • centos服务器安装docker和Rabbitmq
  • 【Redis】Redis高级特性和应用(慢查询、Pipeline、事务、Lua)
  • 【pytorch】深度学习入门一:pytorch的安装与配置(Windows版)
  • 安装postgresql驱动及python使用pyodbc指定postgresql驱动调用postgresql
  • 【OpenCV】计算机视觉图像处理基础知识
  • Course1-Week3-分类问题
  • Dockerfile 指令的最佳实践
  • Drools 入门:折扣案例
  • 微信小程序中生命周期钩子函数
  • “无忧文件安全!上海迅软DSE文件加密软件助您轻松管控分公司数据!
  • 详解线段树
  • C语言——指针的运算
  • Apache Hive(部署+SQL+FineBI构建展示)
  • python入门级简易教程
  • 模拟一个集合 里面是设备号和每日的日期
  • antdesign前端一直加载不出来
  • 排序算法介绍(一)插入排序
  • 2023新优化应用:RIME-CNN-LSTM-Attention超前24步多变量回归预测算法