【JavaEE】UDP数据报套接字—实现回显服务器(网络编程)

news2024/11/14 17:17:09

  • 博主简介:想进大厂的打工人
  • 博主主页:@xyk:
  • 所属专栏: JavaEE初阶

本篇文章将带你了解什么是网络编程?

网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)。

网络编程中需要有发送端,接收端,也就是服务器和客户端进行数据交互。

最常见的场景,客户端是指给用户使用的程序,服务端是提供用户服务的程序:
1. 客户端先发送请求到服务端
2. 服务端根据请求数据,执行相应的业务处理
3. 服务端返回响应:发送业务处理结果
4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)


目录

文章目录

一、Socket套接字

1.1 概念

1.2 分类

1.3 TCP和UDP的特点

二、DatagramSocket API

三、DatagramPacket API

四、基于UDP Socket实现回显服务器

4.1 服务器端

4.1.1 创建Socket对象

 4.1.2 绑定端口号

4.1.3 启动服务器主逻辑

4.2 客户端

 五、Socket文件怎么是存储数据的

 六、测试udp回显服务器

 七、udp英语查询服务器


一、Socket套接字

1.1 概念

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

程序猿写网络程序,主要编写的应用层代码!!

真正要发送这个数据,需要上层协议,调用下层协议,应用层需要调用传输层。(想了解协议分层,请看【JavaEE】网络通信中的一些基本概念及协议分层_xyk:的博客-CSDN博客

传输层给应用层提供一组api,统称为socket api

1.2 分类

系统给程序猿提供了两组socket api

1.基于UDP的api(User Datagram Protocol)

2.基于TCP的api(Transmission Control Protocol)

1.3 TCP和UDP的特点

UDP:                                         TCP:

无连接                                        有连接

不可靠传输                                 可靠传输

面向数据报                                 面向字节流

全双工                                        全双工

所谓的无连接:是指使用UDP通信的双方,不需要刻意保存对端的相关信息

 

不可靠传输:消息发了就发了,不关注结果了

面向数据报:以一个UDP数据报为基本单位

全双工:一条路径,双向通信

所谓的有连接:使用TCP通信的双方,则需要刻意保存对方的相关信息

 

可靠传输:不是说,发了就100%能够到达对方,而是尽可能的传输过去(知道结果)

面向字节流:以字节为传输的基本单位,读写方式非常灵活

全双工:一条路径,双向通信

半双工:

二、DatagramSocket API

  • Socket ==> 数据报的Socket对象
  • Packet ==> 这个对象就是一个UDP数据报

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

Socket,说明这个对象是一个socket对象,相当于对应到系统中一个特殊的文件(socket文件)

socket文件并非对应到硬盘上的某个数据存储区域,而是对应到,网卡这个硬件设备

(cmd中输出ipconfig查看):

有线网卡:

 

所以想要进行网络通信,就需要有socket文件这样的对象

借助这个socket文件对象,才能间接的操作网卡(遥控器)

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

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

DatagramSocket 构造方法:

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

此处的Socket对象,对于服务器这边的socket往往要关联一个具体的端口号(必须要不变!!)

客户端这边则不需要手动指定,系统自动分配即可(则不要求)

举例说明一下:

 而客户端这边,不需要有地址,只需要知道餐厅在哪就行,坐在哪里吃都行,是随机的~~~

DatagramSocket 方法:

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

socket也是文件,文件用完了要记得关闭!否则会出现文件资源泄漏的问题!!

三、DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报
DatagramPacket 构造方法:

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

第一个版本,不需要设置地址进去,通常用来接受消息

第二个版本,需要显式的设置地址进去,通常用来发送消息

DatagramPacket 方法

方法签名方法说明
InetAddress
getAddress()
从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取
接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获
取接收端主机端口号
byte[] getData()获取数据报中的数据
  • InetAddress是对服务器IP地址的包装
  • 端口号代表服务器程序所在的“位置”

四、基于UDP Socket实现回显服务器

回显服务器(echo server)

客户端发了个请求,服务器返回一个一模一样的响应~~

三个核心工作:

  1. 读取请求并解析
  2. 根据请求求得对应响应(回显服务器 无此操作)
  3. 把响应返回给客户端

4.1 服务器端

4.1.1 创建Socket对象

需要先定义一个 socket 对象

通过网络通信,必须要使用 socket对象

 4.1.2 绑定端口号

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

4.1.3 启动服务器主逻辑

需要先构造一个空饭盒并接收:

类似去食堂打饭,带着空饭盒去(只有内存空间,没有有意义的数据),让大妈给打饭~~

传一个空的packet对象,然后由receive方法内部,把参数的这个packet进行填充 

此时,如果还没有客户端发来的数据,怎么办?

  • receive阻塞等待就行了,直到客户端发来真的数据请求
  • 有点类似于阻塞队列~~

为了方便处理,把数据报转成String

这个操作并非是必须的,只是此处为了后续代码简单,就简单的构造一个String,

如果客户端发来的数据是“老板来份蛋炒饭”,此时这个数据就会以二进制的形式躺在requestPackct中的字节数组中,把这个字节数组拿出来,重新构造一个String,这个String 的内容就是“老板来一份蛋炒饭”

根据请求计算响应(此处省略这个步骤)

 

 把响应结果写回客户端,并打印日志

  • getSocketAddress === 数据报里的客户端主机IP
  • 传给客户端得转化为数据报才行
  • 而计算数据报的信息计算只能以字符串为对象

 SocketAddress同时包含了 ip 和 端口号

完整代码:

package network;

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

/**
 * @author xyk的电脑
 * @version 1.0
 * @description: TODO
 * @date 2023/4/6 16:48
 */
public class UdpEchoServer {
    //需要先定义一个 socket 对象
    //通过网络通信,必须要使用 socket对象
    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
            String request = new String(requestPacket.getData(),0,
                    requestPacket.getLength());
            // 2. 根据请求计算响应(此处省略这个步骤)
            String response = process(request);
            // 3. 把响应结果写回到客户端
            //    根据 response 字符串, 构造一个 DatagramPacket .
            //    和请求 packet 不同, 此处构造响应的时候, 需要指定这个包要发给谁.
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    // requestPacket 是从客户端这里收来的. getSocketAddress 就会得到客户端的 ip 和 端口
                    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);
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();
    }
}

4.2 客户端

4.2.1 客户端启动,需要知道服务器在哪里!!

对于客户端不需要指定关联端口,不代表没有端口,而是系统自动分配了端口

4.2.2 用户输入内容

 4.2.3 把字符串构造成 UDP packet, 并进行发送.

这个构造,也是把数据构造成DatagramPacket,一方面需要String中的getBytes数组

另一方面,需要指定服务器的 ip 和 端口,此处不是通过InetAddress直接构造了,而是分开设置

4.2.4 把响应数据转换成 String 显示出来.


完整代码:

package network;

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

/**
 * @author xyk的电脑
 * @version 1.0
 * @description: TODO
 * @date 2023/4/6 16:48
 */
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

    // 客户端启动, 需要知道服务器在哪里!!
    public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
        // 对于客户端来说, 不需要显示关联端口.
        // 不代表没有端口, 而是系统自动分配了个空闲的端口.
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true){
            // 1. 先从控制台, 读取一个字符串过来
            //    先打印一个提示符, 提示用户要输入内容
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 把字符串构造成 UDP packet, 并进行发送.
            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);
            // 4. 把响应数据转换成 String 显示出来.
            String response = new String(responsePacket.getData(),
                    0, responsePacket.getLength());
            System.out.printf("req: %s, resp: %s\n", request, response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
        udpEchoClient.start();
    }

}

小结:

五、Socket文件怎么是存储数据的

 六、测试udp回显服务器

 

 七、udp英语查询服务器

package network;

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xyk的电脑
 * @version 1.0
 * @description: TODO
 * @date 2023/4/9 21:39
 */
public class UdpDictServer extends UdpEchoServer {
    private Map<String,String> dict = new HashMap<>();

    public UdpDictServer(int port) throws SocketException {
        super(port);

        dict.put("dog","小狗");
        dict.put("cat","小猫");
        dict.put("fuck","卧槽");
    }

    @Override
    public String process(String request){
        return dict.getOrDefault(request,"该单词没有查到! ");
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer udpDictServer = new UdpDictServer(9090);
        udpDictServer.start();
    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中断-STM32

中断-STM32 中断:在主程序运行过程中&#xff0c;出现了特定的中断触发条件 (中断源)&#xff0c;使得CPU暂停当前正在运行的程序转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行。 中断优先级:当有多个中断源同时申请中断时&#xff0c;CPU会根据中断源的轻重缓…

Java程序猿搬砖笔记(十一)

文章目录 Hexo博客 Next主题图片防盗链问题Springboot Druid数据库密码加密配置步骤Java统计字符串出现的次数Java获取某个字符在字符串中出现第N次的位置Maven激活指定profileMaven中resources标签的用法详解MySQL 字符集不一致报错EasyExcel日期格式化Configuration、Compone…

gradle Task 详解

Task定义和配置 查看工程下所有的task&#xff0c;使用如下命令 gradle tasks 定义一个task task创建的源码 参数分别是 task 名称&#xff0c;和一个 closure。groovy语法的closure可以写在小括号外面&#xff0c;小括号可以省略 task的源码 public interface Task extends…

【Java笔试强训 25】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;星际密码…

RabbitMQ死信队列延迟交换机

RabbitMQ死信队列&延迟交换机 1.什么是死信 死信&死信队列 死信队列的应用&#xff1a; 基于死信队列在队列消息已满的情况下&#xff0c;消息也不会丢失实现延迟消费的效果。比如&#xff1a;下订单时&#xff0c;有15分钟的付款时间 2. 实现死信队列 2.1 准备E…

网络编程代码实例:IO复用版

文章目录 前言代码仓库内容代码&#xff08;有详细注释&#xff09;server.cclient_select.cclient_poll.cclient_epoll.c 结果总结参考资料作者的话 前言 网络编程代码实例&#xff1a;IO复用版。 代码仓库 yezhening/Environment-and-network-programming-examples: 环境和…

[Linux]网络连接、资源共享

​⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Linux基础操作。本文主要是分享一些Linux系统常用操作&#xff0c;内容主要来源是学校作业&#xff0c;分享出来的…

详解c++---vector模拟实现

目录标题 准备工作构造函数迭代器的完善性质相关的函数实现reservepush_back[ ]emptyresizeinserteraseerase后迭代器失效问题swapclear~vector老式拷贝构造迭代器构造新式拷贝构造老式赋值重载新式赋值重载N个数据的构造vector的浅拷贝问题 准备工作 首先我们知道vector是一个…

HTB靶机06-Beep-WP

beep 靶机IP&#xff1a;10.10.10.7 攻击机IP&#xff1a;10.10.14.6 web RCE漏洞利用、nmap提权 扫描 nmap 常规扫描&#xff1a; ┌──(xavier㉿xavier)-[~/HTB/005-Beep] └─$ sudo nmap -sSV -sC 10.10.10.7 -oN nmap1.out Starting Nmap 7.91 ( https://nmap.org …

《道德经》

《道德经》是春秋时期老子&#xff08;李耳&#xff09;的哲学作品&#xff0c;又称《道德真经》、《老子》、《五千言》、《老子五千文》&#xff0c;是中国古代先秦诸子分家前的一部著作&#xff0c;是道家哲学思想的重要来源。 道德经分上下两篇&#xff0c;原文上篇《德经…

网络安全: CIDR无类别路由

网络安全&#xff1a; CIDR无类别路由 CIDR是无类别路由&#xff0c;出现CIDR的原因是因为ipv4的地址被使用完客&#xff0c;CIDR的出现暂缓了ipv4用完的速度。 原本的ipv4很刻板&#xff0c;网络号分成8位&#xff0c;16位&#xff0c;24位作为掩码&#xff0c;也就是 xxx.0…

DRY编码原则

基本情况 DRY&#xff0c;Don’t repeat yourself&#xff0c;就是不要重复你自己的意思。 不要重复&#xff0c;是多么简单的意思了&#xff0c;重复就是多了一个一样的东西&#xff0c;为什么多一个呢&#xff0c;一个就可以了&#xff0c;这样才简单&#xff0c;这是一个常…

【报错】arXiv上传文章出现XXX.sty not found

笔者在overleaf上编译文章一切正常&#xff0c;但上传文章到arxiv时出现类似于如下报错&#xff1a; 一般情况下观察arxiv的编译log&#xff0c;不通过的原因&#xff0c;很多时候都是由于某一行导入了啥package&#xff0c;引起的报错&#xff1b;但是如果没有任何一个具体的…

AppSmith(安装与练习4套)

AppSmith官网文档&#xff1a; https://docs.appsmith.com/getting-started/setup/installation-guides/docker安装前需要已经安装好docker&#xff0c;需要版本如下&#xff1a; Docker ( 20.10.7或者更高) Docker-Compose ( 1.29.2或者更高) 安装Appsmith&#xff1a; 准备…

【Linux】第二站:Linux基本指令(一)

文章目录 一、操作系统OS概念1.OS是什么&#xff1f;2.为什么要有OS?1.一个好的操作系统&#xff0c;他的衡量指标是什么&#xff1f;2.操作系统的核心工作 3.理解我们在计算机上的操作4.Linux和Windows的特点 二、Linux基本指令1. 指令概述2.ls指令1> ls -l2> ls -a3&g…

ChatGPT其实并不想让开发人员做这5件事情

前言 ChatGPT已经火爆了快半年了吧&#xff0c;紧接着国内也开始推出了各种仿制品&#xff0c;我甚至一度怀疑&#xff0c;如果人家没有推出ChatGPT&#xff0c;这些仿制品会不会出现。而很多人也嗨皮得不行&#xff0c;利用各种方法开始科学上网&#xff0c;用ChatGPT做各种觉…

不得不说的行为型模式-解释器模式

解释器模式&#xff1a; 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种语言&#xff0c;用于解释执行特定的操作&#xff0c;例如正则表达式、查询语言、数学表达式等。该模式通过定义一个解释器来解释语言中的表达式…

分治与减治算法实验:题目6 淘汰赛冠军问题

目录 前言 实验内容 实验流程 实验分析 实验过程 流程演示 写出伪代码 实验代码 运行结果 改进算法 总结 前言 淘汰赛冠军问题是一个经典的算法设计与分析的问题&#xff0c;它要求我们在给定的n个参赛者中&#xff0c;通过一系列的比赛&#xff0c;找出最终的冠军…

nginx负载均衡+RabbitMq集群及镜像队列(2)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、nginx是什么&#xff1f;二、搭建步骤1.软件和环境2.安装nginx3.负载均衡配置nginx.conf4.应用程序配置 总结 前言 提示&#xff1a;这里可以添加本文要记…

Linux套接字编程-3

在之前的套接字编程内容中&#xff0c;我们讲述完了UDP和TCP的主要内容&#xff0c;但是对于TCP通信中具体的实现还存在一些问题没有解决&#xff0c;所以我们本篇博客将对进行分析和解决。 目录 1.引入 2.多进程 3.多线程 1.引入 在上一篇博客中&#xff0c;当我们使用T…