FPGA - 以太网UDP通信(三)

news2024/10/5 18:27:43

一,引言

前文链接:FPGA - 以太网UDP通信(一)

                  FPGA - 以太网UDP通信(二)

在以上文章中介绍了以太网简介,以太网UDP通信硬件结构,以及PHY芯片RGMII接口-GMII接口转换逻辑,以及数据链路层(MAC层)接受发送逻辑。接下来介绍UDP通信IP层接受发送逻辑。

二,以太网UDP通信结构框图

在   FPGA - 以太网UDP通信(二)中画出了以太网UDP通信简易结构框图,在mac_layer中使用双fifo来处理跨时钟域处理,并且在mac层的MAC帧格式中:(类型/长度   2byte  小于1536表示长度,大于1536表示类型 arp:16'h0806 , ip: 16'h0800 )所以在设计中预留arp接口。

优化后的结构框图如下:

三,IP层数据帧

IP数据报格式如下图所示,IP 数据报文由首部(称为报头)数据两部分组成。首部的前一部分是固定长度,共 20 字节(如图所示前五行为IP首部),是所有 IP 数据报必须具有的。在首部的固定部分的后面是一些可选字段,其长度是可变的。

IP 协议首部详解

---------------------------------------------------IP首部 20byte---------------------------------------------------

版本 + 首部长度  1byte

  • 版本:占4位,指的是IP协议的版本,通信双方的版本必须一致,当前主流版本是4,即IPv4,也有IPv6
  • 首部长度:占4位,最大数值为15,表示的是IP首部的长度,单位是“32位字”(4个字节),也就是IP首部最大长度为60字节

        版本ipv4 : 4'h4 ,首部长度 : 4'h5

服务类型   1byte
        一般为8'h0

总长度     2byte
        (ip首部长度 + ip数据包长度)占16位,最大数值为65535,表示的是IP数据报总长度(IP首部+IP数据) (在前边介绍数据链路层的时候,也提到过一个长度。对于数据链路层的长度,称之为MTU,一般为1500字节。而IP数据报的最大长度有65535个字节,比MTU要大。如果真正传输的时候,如果出现这种情况,数据链路层会对IP数据报进行分片,也就是将一个较长的IP数据报拆分成多个数据帧来进行传输)

标识       2byte
        复位给0,发完一包数据自加1

标记 + 分段偏移 2byte

  • 标记:3bit。最高位保留为0;中间位是否开启分段,0不开启,1开启;最低位表示是否存在下一个分段,0表示为最后一个分段,1表示还存在下一个分段。一般默认为3’b010
    分段偏移:表示第0段,第1段.....
  • 片偏移:前边有提到,如果IP数据报的长度过长,会进行IP报文的分片,把一个IP报文拆分成多个数据帧进行数据链路层的传输。因此,如果拆分的话,就需要使用片偏移来记录当前的数据帧,保存的第几个偏移的IP数据

生存时间(TTL)  1byte
        表明IP数据报文在网络中的寿命,每经过一个设备(不管是路由器还是计算机),TTL减一,当TTL=0时,网络设备必须丢弃该报文(它解决的就是,当网络报文找不到终点的时候,避免网络报文在网络中无限的传输,以消耗带宽)
win系统默认为8‘h80

协议  1byte

        表明IP数据所携带的具体数据是什么协议的(如TCP、UDP等)
udp : 8'd17   ,tcp : 8'd6  , icmp : 8'd1

首部校验和  2byte

        校验IP首部是否有出错(接收方接收到IP首部之后也会进行校验,如果有错,则直接丢弃)

源ip地址 4byte

        发送IP数据报的网络设备的IP地址

目的ip地址 4byte

        IP数据报要到达的目的网络设备的IP地址        

---------------------------------------------------------------------------------------------------------------------------

IP 首部校验和算法

        首部检验和字段是根据IP首部计算的检验和码,不对首部后面的数据进行计算 。其计算方法为:

        1. 将校验和字段置为0, 然后将IP包头按16比特分成多个单元,如包头长度不是16比特的倍数,则用 0 比特填充到 16 比特的倍数;
        2. 对各个单元采用反码加法运算(即高位溢出位会加到低位 通常的补码运算是直接丢掉溢出的高位)将得到的和的反码填入校验和字段;

四,IP层代码设计

首先,在上面优化后的结构框图中可以看到,在mac_receiv输出的数据经过校验,数据是输入到arp还是ip层,因此要设计一个mac_to_arp_ip模块

其次,ip层的接受和发送逻辑和mac层的接受发送逻辑类似,并且在mac层已经完成了跨时钟域转换,所以只需要在ip_receive中要完成数据解包校验,在ip_send中要完成数据组包,就完成了整个ip_layer的设计。

mac_to_arp_ip模块

`timescale 1ns / 1ps

module mac_to_arp_ip(
	input					        clk,
	input                           reset,

	/*-------mac_receive模块交互的信号-------------*/	
	input                           mac_rx_data_vld  ,
	input                           mac_rx_data_last ,
	input        [7:0]              mac_rx_data      ,
	input        [15:0]             mac_rx_frame_type,

	/*-------ip_receive模块交互的信号----------------*/	
	output  reg                     ip_rx_data_vld   ,
	output  reg                     ip_rx_data_last  ,
	output  reg  [7:0]              ip_rx_data       ,

	/*-------arp相关的的信号--------------------------*/	
	output  reg                     arp_rx_data_vld   ,
	output  reg                     arp_rx_data_last  ,
	output  reg  [7:0]              arp_rx_data       
 
    );

localparam 	ARP_TYPE = 16'h0806;
localparam  IP_TYPE  = 16'h0800;

always @(posedge clk) begin
    if (mac_rx_frame_type == IP_TYPE) begin
    	ip_rx_data_vld  <= mac_rx_data_vld;   
    	ip_rx_data_last <= mac_rx_data_last;
    	ip_rx_data      <= mac_rx_data;
    end 
    else begin
    	ip_rx_data_vld  <= 0;   
    	ip_rx_data_last <= 0;
    	ip_rx_data      <= 0;    	
    end   
end


always @(posedge clk) begin
    if (mac_rx_frame_type == ARP_TYPE) begin
    	arp_rx_data_vld  <= mac_rx_data_vld;   
    	arp_rx_data_last <= mac_rx_data_last;
    	arp_rx_data      <= mac_rx_data;    	
    end 
    else begin
    	arp_rx_data_vld  <= 0;   
    	arp_rx_data_last <= 0;
    	arp_rx_data      <= 0;    	
    end   
end










endmodule

ip_receive模块

`timescale 1ns / 1ps

module ip_receive #(
	parameter		LOCAL_IP_ADDR  = 32'h0
)(
	input					        clk,
	input                           reset,

	/*-------mac_to_arp_ip模块交互的信号------------  */	
	input                           ip_rx_data_vld   ,
	input                           ip_rx_data_last  ,
	input        [7:0]              ip_rx_data       ,

	/*-------udp_receive模块交互的信号------------  */	
	output  reg                     udp_rx_data_vld  ,
	output  reg                     udp_rx_data_last ,
	output  reg  [7:0]              udp_rx_data      ,	
	output  reg  [15:0]             udp_rx_length    ,

	/*-------icmp的信号-----------------------------  */		
	output  reg                     icmp_rx_data_vld  ,
	output  reg                     icmp_rx_data_last ,
	output  reg  [7:0]              icmp_rx_data      ,	
	output  reg  [15:0]             icmp_rx_length    

    );

localparam  UDP_TYPE  = 8'd17;
localparam  ICMP_TYPE = 8'd1;


reg [10:0] rx_cnt;
reg [31:0] rx_target_ip;
reg [7:0]  ip_protocol;
reg [15:0] total_length;

/*------------------------------------------*\
                 cnt
\*------------------------------------------*/
always @(posedge clk) begin
    if (reset) 
        rx_cnt <= 0;
    else if (ip_rx_data_vld) 
        rx_cnt <= rx_cnt + 1;
    else 
        rx_cnt <= 0;
end

/*------------------------------------------*\
         获取总长度、协议类型、目的IP地址
\*------------------------------------------*/
always @(posedge clk) begin
    if (rx_cnt == 2 || rx_cnt == 3) 
        total_length <= {total_length[7:0],ip_rx_data};
    else 
        total_length <= total_length;
end

always @(posedge clk) begin
    if (rx_cnt == 9) 
        ip_protocol <= ip_rx_data;
    else 
        ip_protocol <= ip_protocol;
end

always @(posedge clk) begin
    if (rx_cnt > 15 && rx_cnt < 20) 
        rx_target_ip <= {rx_target_ip[23:0],ip_rx_data}; 
    else 
        rx_target_ip <= rx_target_ip;
end

/*------------------------------------------*\
                    输出UDP
\*------------------------------------------*/
always @(posedge clk) begin
    if (ip_protocol == UDP_TYPE && rx_target_ip == LOCAL_IP_ADDR && rx_cnt >= 20) begin
    	udp_rx_data_vld  <= ip_rx_data_vld;
    	udp_rx_data_last <= ip_rx_data_last;
    	udp_rx_data      <= ip_rx_data;
    	udp_rx_length    <= total_length - 20;
    end
        
    else begin
    	udp_rx_data_vld  <= 0;
    	udp_rx_data_last <= 0;
    	udp_rx_data      <= 0;
    	udp_rx_length    <= 0;
    end   
end

/*------------------------------------------*\
                    输出ICMP
\*------------------------------------------*/
always @(posedge clk) begin
    if (ip_protocol == ICMP_TYPE && rx_target_ip == LOCAL_IP_ADDR && rx_cnt >= 20) begin
    	icmp_rx_data_vld  <= ip_rx_data_vld;
    	icmp_rx_data_last <= ip_rx_data_last;
    	icmp_rx_data      <= ip_rx_data;
    	icmp_rx_length    <= total_length - 20;
    end
        
    else begin
    	icmp_rx_data_vld  <= 0;
    	icmp_rx_data_last <= 0;
    	icmp_rx_data      <= 0;
    	icmp_rx_length    <= 0;
    end   
end

endmodule

ip_send模块

`timescale 1ns / 1ps

module ip_send #(
	parameter		LOCAL_IP_ADDR  = 32'h0,
	parameter       TARGET_IP_ADDR = 32'h0	
)(
	input					        clk,
	input                           reset,

	/*-------udp_send模块交互的信号------------------*/	
	input                           udp_tx_data_vld  ,
	input                           udp_tx_data_last ,
	input        [7:0]              udp_tx_data      ,	
	input        [15:0]             udp_tx_length    ,

	/*-------mac_send模块交互的信号------------------*/	

	output  reg                     ip_tx_data_vld   ,
	output  reg                     ip_tx_data_last  ,
	output  reg  [15:0]             ip_tx_length     ,
	output  reg  [7:0 ]             ip_tx_data

    );

reg  [10:0] tx_cnt;
wire [7:0]  udp_tx_data_delay; //udp_tx_data打20拍
reg  [15:0] package_id; //标识

reg  [15:0] ip_head_chack;
reg  [31:0] add0;
reg  [31:0] add1;
reg  [31:0] add2;
reg  [31:0] chack_sum;

/*------------------------------------------*\
                 锁存length
\*------------------------------------------*/

always @(posedge clk) begin
    if (udp_tx_data_vld) 
        ip_tx_length <= udp_tx_length + 20;
    else 
        ip_tx_length <= ip_tx_length;
end

/*------------------------------------------*\
                  tx_cnt
\*------------------------------------------*/

always @(posedge clk) begin
    if (reset) 
        tx_cnt <= 0;
    else if (tx_cnt == ip_tx_length - 1)
    	tx_cnt <= 0;
    else if (udp_tx_data_vld || tx_cnt != 0) 
        tx_cnt <= tx_cnt + 1;
    else 
        tx_cnt <= tx_cnt;
end

/*------------------------------------------*\
            组包:IP头部 + IP有效数据
\*------------------------------------------*/
always @(posedge clk) begin
    if (reset) 
        ip_tx_data <= 0;
    else begin
    	case(tx_cnt)
    		0  : ip_tx_data <= {4'h4,4'h5}; //版本加首部长度

    		1  : ip_tx_data <= 0;           //服务类型为0

    		2  : ip_tx_data <= ip_tx_length[15:8];  //总长度
    		3  : ip_tx_data <= ip_tx_length[7:0] ;

    		4  : ip_tx_data <= package_id[15:8];   //标识
    		5  : ip_tx_data <= package_id[7:0];

    		6  : ip_tx_data <= {3'b010,5'h0};     //标记 + 分段偏移
    		7  : ip_tx_data <= 8'h0;    

    		8  : ip_tx_data <= 8'h80;      //固定值,win系统固定位128 = 8‘h80
 
    		9  : ip_tx_data <= 8'd17;      //udp

    		10 : ip_tx_data <= ip_head_chack[15:8];		//ip首部校验    		    		    		
    		11 : ip_tx_data <= ip_head_chack[7:0];

    		12 : ip_tx_data <= LOCAL_IP_ADDR[31:24];  
    		13 : ip_tx_data <= LOCAL_IP_ADDR[23:16];
    		14 : ip_tx_data <= LOCAL_IP_ADDR[15:8];
    		15 : ip_tx_data <= LOCAL_IP_ADDR[7:0];

    		16 : ip_tx_data <= TARGET_IP_ADDR[31:24];
    		17 : ip_tx_data <= TARGET_IP_ADDR[23:16];
    		18 : ip_tx_data <= TARGET_IP_ADDR[15:8];
    		19 : ip_tx_data <= TARGET_IP_ADDR[7:0];

    		default : ip_tx_data <= udp_tx_data_delay;
    	endcase
    end
end


always @(posedge clk) begin
    if (tx_cnt == ip_tx_length - 1) 
        ip_tx_data_last <= 1'b1;
    else 
        ip_tx_data_last <= 1'b0; 
end

always @(posedge clk) begin
    if (ip_tx_data_last) 
        ip_tx_data_vld <= 1'b0;
    else if (udp_tx_data_vld) 
        ip_tx_data_vld <= 1'b1;
    else 
        ip_tx_data_vld <= ip_tx_data_vld;
end

/*------------------------------------------*\
                  标识
\*------------------------------------------*/
always @(posedge clk) begin
    if (reset) 
        package_id <= 0;
    else if (ip_tx_data_last) 
        package_id <= package_id + 1;
    else 
        package_id <= package_id; 
end

/*------------------------------------------*\
               计算IP首部校验和
\*------------------------------------------*/
always @(posedge clk) begin  // 2个clk
	add0      <= 16'h4500 + ip_tx_length + package_id;
	add1      <= 16'h4000 + {8'h80,8'd17} + LOCAL_IP_ADDR[31:16];
	add2      <= LOCAL_IP_ADDR[15:0] + TARGET_IP_ADDR[31:16] + TARGET_IP_ADDR[15:0];
	chack_sum <= add0 + add1 + add2;
end

always @(posedge clk) begin
    if (reset) 
        ip_head_chack <= 0;
    else if (tx_cnt == 5) 
        ip_head_chack <= chack_sum[31:16] + chack_sum[15:0];
    else if (tx_cnt == 6)
        ip_head_chack <= ~ip_head_chack;
    else 
    	ip_head_chack <= ip_head_chack;
end

/*------------------------------------------*\
                  打拍
\*------------------------------------------*/
//注意 : 如果A的值为19,udp_tx_data_delay打拍为20拍
c_shift_ram_0 ip_delay (
  .A(19),      // input wire [5 : 0] A
  .D(udp_tx_data),      // input wire [7 : 0] D
  .CLK(clk),  // input wire CLK
  .Q(udp_tx_data_delay)      // output wire [7 : 0] Q
);

endmodule

顶层设计

ip层分别实现了接收和发送两部分,将两部分例化封装顶层ip_layer

`timescale 1ns / 1ps

module ip_layer #(
	parameter		LOCAL_IP_ADDR  = 32'h0,
	parameter       TARGET_IP_ADDR = 32'h0		
)(

	input						    app_tx_clk       ,
	input                           app_rx_clk       ,

	input                           app_rx_reset     ,
	input                           app_tx_reset     ,

	input                           ip_rx_data_vld   ,
	input                           ip_rx_data_last  ,
	input        [7:0]              ip_rx_data       ,

	output                          ip_tx_data_vld   ,
	output                          ip_tx_data_last  ,
	output       [15:0]             ip_tx_length     ,
	output       [7:0 ]             ip_tx_data       ,

	output                          udp_rx_data_vld  ,
	output                          udp_rx_data_last ,
	output       [7:0]              udp_rx_data      ,	
	output       [15:0]             udp_rx_length    ,

	input                           udp_tx_data_vld  ,
	input                           udp_tx_data_last ,
	input        [7:0]              udp_tx_data      ,	
	input        [15:0]             udp_tx_length    ,	

	output                          icmp_rx_data_vld  ,
	output                          icmp_rx_data_last ,
	output       [7:0]              icmp_rx_data      ,	
	output       [15:0]             icmp_rx_length    
);

	ip_receive #(
			.LOCAL_IP_ADDR(LOCAL_IP_ADDR)
		) ip_receive (
			.clk               (app_rx_clk),
			.reset             (app_rx_reset),

			.ip_rx_data_vld    (ip_rx_data_vld),
			.ip_rx_data_last   (ip_rx_data_last),
			.ip_rx_data        (ip_rx_data),

			.udp_rx_data_vld   (udp_rx_data_vld),
			.udp_rx_data_last  (udp_rx_data_last),
			.udp_rx_data       (udp_rx_data),
			.udp_rx_length     (udp_rx_length),

			.icmp_rx_data_vld  (icmp_rx_data_vld),
			.icmp_rx_data_last (icmp_rx_data_last),
			.icmp_rx_data      (icmp_rx_data),
			.icmp_rx_length    (icmp_rx_length)
		);

	ip_send #(
			.LOCAL_IP_ADDR(LOCAL_IP_ADDR),
			.TARGET_IP_ADDR(TARGET_IP_ADDR)
		) ip_send (
			.clk              (app_tx_clk),
			.reset            (app_tx_reset),

			.udp_tx_data_vld  (udp_tx_data_vld),
			.udp_tx_data_last (udp_tx_data_last),
			.udp_tx_data      (udp_tx_data),
			.udp_tx_length    (udp_tx_length),

			.ip_tx_data_vld   (ip_tx_data_vld),
			.ip_tx_data_last  (ip_tx_data_last),
			.ip_tx_length     (ip_tx_length),
			.ip_tx_data       (ip_tx_data)
		);

endmodule

五,总结

至此,我们完成了IP层的发送与接受。同时,也已经了解了IP协议首部的具体内容,IP数据包就是紧跟在IP协议首部后面的 。 然后, IP的数据部分也还并不是单纯的用户数据, 我们在网络应用时 ,还需要将我们的用户数据 进一步打包到比IP协议更上一 层 的协议中, 再通过 IP 协议发送。

接下来,在下一篇博客中将会实现udp层的接收与发送。

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

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

相关文章

Node.js从基础到高级运用】二十三、Node.js中自动重启服务器

引言 在Node.js开发过程中&#xff0c;我们经常需要修改代码后重启服务器来应用这些更改。手动重启不仅效率低下&#xff0c;而且会打断开发流程。幸运的是&#xff0c;有一些工具可以帮助我们自动化这个过程。本文将介绍如何使用nodemon来实现Node.js服务器的自动重启。 什么是…

清楚明了的凸松弛最优潮流!基于混合整数二阶锥规划的主动配电网最优潮流研究程序代码!

前言 最优潮流(optimal power flow&#xff0c;OPF)问题&#xff0c;是电力系统中最常见、最基础的一类优化问题。在满足基尔霍夫定律、线路容量约束以及运行安全约束等电力网络物理约束的前提下&#xff0c;OPF问题旨在寻找一个最优的潮流稳态工作点&#xff0c;使得在该工作…

【LAMMPS学习】八、基础知识(2.5)恒压器

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

WebSocket一篇讲清楚

文章目录 WebSocket简介WebSocket与HTTP的区别WebSocket的工作原理WebSocket的应用场景WebSocket的使用WebSocket 属性WebSocket 事件WebSocket 方法 WebSocket的心跳机制WebSocket 的安全性和跨域问题如何处理&#xff1f;有哪些好用的客户端WebSocket第三方库总结 WebSocket简…

代码随想录图论

1. 所有可能的路径 class Solution:def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:def dfs(graph, result, path, root): #result 返回结果, path记录路径, root记录遍历到了第几个节点if root len(graph) - 1: #如果遍历到最后…

C#Winform使用扩展方法自定义富文本框(RichTextBox)字体颜色

实现效果 调用方法 rtxtLog.AppendTextColorful(richTextBox1,DateTime.Now.ToString(), Color.Red); 完整代码如下 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using Sys…

Java 基于微信小程序的汽车4S店客户管理小程序,附源码

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

SpringCloud框架 服务拆分和远程调用

数据库隔离避免耦合度过高&#xff0c;不同模块将自己的业务暴露为接口&#xff0c;供其他微服务调用 微服务远程调用技术Rest 在后端实现发送http请求 1.在启动类/配置类里注册RestTemplate启动对象 2.注入Bean对象使用

【力扣】17.04.消失的数字

这道题的题目意思就是从0-n中的数字中找出缺失的那一个&#xff0c;n是数组的长度&#xff0c;因此我的想法就是先将数组进行排序&#xff0c;往sort&#xff08;&#xff09;里面一扔&#xff0c;完了以后看前一个与后一个之差中哪个不是等于1的&#xff0c;就求出来即可。 法…

去除pycharm运行pytest的默认参数--no-header --no-summary -q

进入pycharm设置(Settings)&#xff0c;找到高级设置(Advanced Settings)—>Python–>Pytest&#xff1a;不添加"–no-header --no-summary -q"(Pytest&#xff1a;do not add “–no-header --no-summary -q”)

R语言计算:t分布及t检验

t分布理论基础 t分布也称Student’s t-distribution&#xff0c;主要出现在小样本统计推断中&#xff0c;特别是当样本量较小且总体标准差未知时&#xff0c;用于估计正态分布的均值。其定义基于正态分布和 X 2 X^{2} X2分布&#xff08;卡方分布&#xff09;。如果随机变量X服…

pytorch-多分类实战之手写数字识别

目录 1. 网络设计2. 代码实现2.1 网络代码2.2 train 3. 完整代码 1. 网络设计 输入是手写数字图片28x28&#xff0c;输出是10个分类0~9&#xff0c;有两个隐藏层&#xff0c;如下图所示&#xff1a; 2. 代码实现 2.1 网络代码 第一层将784降维到200&#xff0c;第二次使用…

Linux的学习之路:7、yum与git

摘要 本章主要是说一下yum和git的操作 目录 摘要 一、什么是yum 二、yum三板斧 1、list 2、install 3、remove 三、怎么创建仓库 四、git三板斧 1、add 2、commit 3、push 4、pull 五、思维导图 一、什么是yum YUM是Yellowdog Updater Modified的简称&#xf…

三方库移植之NAPI开发(三)通过IDE开发NAPI工程

在三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI一文中&#xff0c;笔者开发的是一个rom包的napi工程。该工程需要编译烧录固件&#xff0c;C 的动态库会集成到开发板的ROM中。在本篇文章中&#xff0c;笔者使用三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI中一样的he…

zabbix监控配置(添加主机、主机组和添加监控项等)

zabbix监控配置 文章目录 zabbix监控配置1.添加主机组2.添加主机&#xff08;linux&#xff09;3.添加主机&#xff08;windows&#xff09;4.监控项配置&#xff08;通过模板添加&#xff09;5.监控项配置&#xff08;手动添加&#xff09; 1.添加主机组 2.添加主机&#xff0…

【Github】PwGen用户友好的Web应用密码生成器

弱密码问题一直是网络安全领域的一个重大挑战。许多人为了方便记忆&#xff0c;倾向于使用简单、常见的密码&#xff0c;如“123456”、“password”或者他们的生日等&#xff0c;这些密码很容易被猜测或通过暴力破解方法攻破。弱密码的使用大大增加了账户被黑客入侵的风险&…

【深入解析spring cloud gateway】13 Reactive Feign的使用

问题引入 在gateway中如果使用feignClient的话&#xff0c;会报如下错误 java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3at reactor.core.publisher.BlockingSingleSubscriber.bloc…

C++实现一个自定义字符串类(string)

本博客将详细介绍如何在C中实现一个自定义的字符串类 string&#xff0c;这个类模仿了标准库中 std::string 的关键功能。这个过程将涵盖从声明到定义的每一步&#xff0c;重点介绍内存管理、操作符重载以及提供一些关键的实现细节。 首先&#xff1a;我们采用函数的声明与定义…

python--字符串对象和

1、找出10000以内能被5或6整除&#xff0c;但不能被两者同时整除的数&#xff08;函数&#xff09; def Divisible_by_5_6(x:int)->list:arr[]for i in range(1,x1):if (i % 5 0 or i % 6 0 ):if i % 5 0 and i % 6 0:continue #利用continue跳过能被5和6整除的数else:a…

Spring Boot 学习(4)——开发环境升级与项目 jdk 升级

各种版本都比较老&#xff0c;用起来也是常出各样的问题&#xff0c;终于找到一个看来不错的新教程&#xff0c;是原先那个教程的升级。遂决定升级一下开发环境&#xff0c;在升级遇到一些问题&#xff0c;摸索将其解决&#xff0c;得些体会记录备查。 最终确定开发环境约束如下…