FPGA - 以太网UDP通信(三)

一,引言

前文链接: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层的接收与发送。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云架构(四)异步请求-应答模式

Asynchronous Request-Reply pattern - Azure Architecture Center | Microsoft Learn 把后台处理和前端解耦&#xff0c;后台处理需要异步处理&#xff0c;但是也需要给前端一个清晰的回应。 背景和问题 在现代应用开发中&#xff0c;代码通常在浏览器中运行&#xff0c;依…

HarmonyOS实战开发-录音机、如何实现音频录制和播放的功能

介绍 本示例使用audio相关接口实现音频录制和播放的功能&#xff0c;使用mediaLibrary实现音频文件的管理。 相关概念&#xff1a; AudioRecorder&#xff1a;音频录制的主要工作是捕获音频信号&#xff0c;完成音频编码并保存到文件中&#xff0c;帮助开发者轻松实现音频录…

麒麟 V10 离线 安装 k8s 和kuboard

目录 安装文件准备 主机准备 主机配置 修改主机名&#xff08;三个节点分别执行&#xff09; 配置hosts&#xff08;所有节点&#xff09; 关闭防火墙、selinux、swap、dnsmasq(所有节点) 安装依赖包&#xff08;所有节点&#xff09; 系统参数设置(所有节点) 时间同步…

【Qt】界面优化

目录 一、QSS 1.1 基本语法 1.2 QSS设置方法 1.2.1 指定控件样式设置 1.2.2 全局样式设置 1.2.3 从文件加载样式表 1.2.4 使用Qt Designer编辑样式 1.3 选择器 1.3.1 介绍 1.3.2 子控件选择器 1.3.3 伪类选择器 1.4 样式属性(盒模型) 1.5 代码示例(登录界面) 二、…

html中的“居中”问题详解(超全)

html中的“居中”问题详解&#xff08;超全&#xff09; 图片居中文本居中定位居中元素居中响应式设计中的居中技巧 引言&#xff1a; 在网页设计和开发中&#xff0c;实现元素的居中是一个常见但也常被低估的挑战。无论是在传统的网页布局中还是在响应式设计中&#xff0c;居中…

DP10RF001一款工作于200MHz~960MHz低功耗、高性能、单片集成的(G)FSK/OOK无线收发芯片

产品概述. DP10RF001是一款工作于200MHz~960MHz范围内的低功耗、高性能、单片集成的(G)FSK/OOK无线收发机芯片。内部集成完整的射频接收机、射频发射机、频率综合器、调制解调器&#xff0c;只需配备简单、低成本的外围器件就可以获得良好的收发性能。芯片支持灵活可设的数据包…

MySQL之sql性能分析

sql执行频率 MySQL客户端连接成功后&#xff0c;通过show[session|global]status命令可以提供服务器状态信息。通过如下指令&#xff0c;可以查看当前数据库的所有INSERT、DELETE、UPDATE、SELECT的访问频次。 慢日志查询 慢查询日志记录了所有执行时间超过指定参数(longquer…

AR地图导览小程序是怎么开发出来的?

在移动互联网时代&#xff0c;AR技术的发展为地图导览提供了全新的可能性。AR地图导览小程序结合了虚拟现实技术和地图导航功能&#xff0c;为用户提供了更加沉浸式、直观的导览体验。本文将从专业性和思考深度两个方面&#xff0c;探讨AR地图导览小程序的开发方案。 编辑搜图 …

MAC系统安装PHP、Java、Python、mysql、Composer等环境无权限问题的详细操作方法说明。

本篇文章主要讲解MAC系统安装PHP、Java、Python、mysql、Composer等环境无权限问题的详细操作方法说明。通过本篇文章你可以快速掌握brew安装相对应环境的能力。 作者&#xff1a;任聪聪 日期&#xff1a;2024年4月12日 一、brew介绍及安装说明 官网地址&#xff1a;https://b…

工具推荐:市面上有哪些AI智能客服机器人比较好用?

在这个客户期望得到即时响应的时代&#xff0c;AI智能客服机器人成为了许多企业提高客户满意度和效率的重要工具。这些机器人利用最新的人工智能技术&#xff0c;可以24/7无休止地回答客户的查询&#xff0c;处理常见问题&#xff0c;甚至在必要时将问题转接给真人客服。接下来…

大数据架构之关系型数据仓库——解读大数据架构(二)

文章目录 前言什么是关系型数仓对数仓的错误认识与使用自上而下的方法关系型数仓的优点关系型数仓的缺点数据加载加载数据的频率如何确定变更数据 关系型数仓会消失吗总结 前言 本文对关系型数据仓库&#xff08;RDW&#xff09;进行了简要的介绍说明&#xff0c;包括什么是关…

50. QT/QML中创建多线程的方式汇总

1. 说明 在QT / QML中创建线程主要有三种方式。第一种:在定义类时继承 QThread 这个类,然后重写父类的虚函数 run(),将子线程需要执行的业务代码放到 run() 函数当中即可。**注意:**这种方式官方已经摒弃了。第二种:使用moveToThread()函数将需要在子线程中执行的函数类移…

OOCT WPF_D3D项目报错无法加载依赖项

运行示例项目报错缺少dll&#xff0c;发现运用了这个大老李&#xff0c;通过添加PATH路径也无法解决&#xff0c;看到debug文件夹下面没有其他的依赖项。 通过depneds工具可以看到 OCCTProxy_D3D.dll 缺少依赖项&#xff0c;图中的缺项都是OCCT生成的模块dll所以讲这些dll从..…

Java基于微信小程序的高校体育场管理小程序,附源码

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

数据结构(图)

定义 G (V, E) 图 (点&#xff0c;边) 图&#xff0c;Graph 点&#xff0c;Vertex 边&#xff0c;edge 有空表&#xff0c;空树&#xff0c;但没有空图 图可以没有边|E| 0&#xff0c;但不能没有一个点 稠密图 &稀疏图 是边的多少决定的 &#xff08;见Ex…

npm 切换成淘宝源,以及遇到npm 报错如何解决

淘宝源&#xff1a;npm config set registryhttps://registry.npmmirror.com/ 然后再npm下 package-lock.json这个删了 npm i再试一下

清远某国企IBM服务器Board故障上门维修

接到一台来自广东清远市清城区某水利大坝国企单位报修一台IBM System x3650 M4服务器无法开机的故障&#xff0c;分享给大家&#xff0c;同时也方便有需要的朋友能及时找到我们快速解决服务器问题。 故障服务器型号&#xff1a;IBM System x3650 M4 服务器使用单位&#xff1a;…

每日两题 / 142. 环形链表 II 146. LRU 缓存(LeetCode热题100)

142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 用哈希记录走过的节点即可 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:Lis…

Swift Zulian Tiger

Swift Zulian Tiger 迅捷祖利安猛虎 16万金&#xff08;游戏币&#xff09; 1万金大概就能兑换460元~600元之间&#xff0c;6400元-9600元&#xff0c;汗颜 故事的一天刚打完BWL&#xff0c;才125金&#xff08;游戏币&#xff09; 本来想下线的结果他们说你太黑了&…

智能售货机:引领便捷生活

智能售货机&#xff1a;引领便捷生活 在这个科技迅速进步的时代&#xff0c;便捷已成为生活的必需。智能售货机作为技术与便利完美结合的产物&#xff0c;正逐渐改变我们的购物方式&#xff0c;为都市生活增添新的活力。 智能售货机的主要优势是它的极致便利性。不论是在地铁…