• 基于FPGA的百兆以太网通信


    一、UDP协议介绍

      UDP是User Datagram Protocol 的简称,中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联)参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC768是UDP的正式规范。UDP在IP报文的协议号是17(即0x17)。

    二、数据、UDP、IP、MAC四个报文的关系

      数据是打包在UDP协议中,UDP协议又是基于IP协议之上的,IP协议又是走MAC层发送的,即从包含关系来说:MAC帧中的数据段为IP数据报,IP报文中的数据段为UDP报文,UDP报文中的数据段为用户希望传输的数据内容,如“Hello,welcome to FPGA !”。下图为使用UDP协议发送“Hello,welcome to FPGA !”的数据层层打包示意图:

     图1

     图2

    三、UDP封包格式

            

       各个字段的组成

         (1) 前导码:

          8'h55、8'h55、8'h55、8'h55、8'h55、8'h55、8'h55、8'hd5

         (2)mac首部:

        

         (3)IP首部:前20个字节是IP首部

           具体的各个字节就不细讲了,讲下IP首部校验和(ip_checksum).

          手动计算:

               在发送数据时,计算IP数据报的校验和,步骤如下:

               a、将校验和字段置为 0 ,然后将IP包头按照16比特分成多个单元,如包头不是16比特的倍数,则用0比特填充到16位比特的倍数;

               b、对各个单元采用反码加法运算(即高位溢出位会加到低位,通常的补码运算时直接丢掉溢出的高位),将得到的和的反码填入校验字段;

        (4)UDP首部

     

     ******* 16位UDP长度:UDP包头 + 数据;

     ******* 16位UDP校验和:要求不高时可以设为全零;

        (5)Crc

            Crc这块是从前导码之后,开始计算,直接例化现有的CRC32。

    四、代码设计

      1 // Time : 2020.04.11 21:22
      2 // Describe : udp_test 
      3 
      4 module udp_test(
      5       rst_n,
      6     
      7     //MII 接口信号    
      8     mii_tx_clk,
      9     mii_tx_en,
     10     mii_tx_er,
     11     mii_tx_data,
     12     
     13     phy_rst_n
     14 );
     15 
     16 input rst_n;
     17 
     18 input  mii_tx_clk;         //MII接口发送时钟,由PHY芯片产生,25MHz
     19 output mii_tx_en;           //MII接口发送数据使能信号,高电平有效
     20 output mii_tx_er;           //发送错误,用以破坏数据包发送
     21 output reg[3:0]mii_tx_data; //MII接口发送数据线,FPGA通过该数据线将需要发送的数据依次送给PHY芯片
     22 output phy_rst_n;           //PHY 复位信号
     23 
     24 assign phy_rst_n = 1'b1;
     25 
     26 parameter des_mac     = 48'hc4_54_44_97_c5_d7;  //目标MAC地址
     27 parameter src_mac     = 48'h00_0a_35_01_fe_c0;  //本机/源MAC地址
     28 parameter type_length = 16'h08_00;                //数据帧类型
     29 parameter data_total_len = 16'd22;                   //数据长度(因为MII接口一个字节分两个时钟,每个时钟4位的方式发送,因此本值为实际数据所占字节数的2倍)
     30 
     31 parameter src_port = 16'd5000;
     32 parameter des_port = 16'd6000;
     33 
     34 parameter ver        = 4'h4;                  //版本
     35 parameter hdr_len    = 4'h5;                //首部长度
     36 parameter tos        = 8'h00;                  //服务类型
     37 //parameter total_len  = ip_total_len;            //IP报文总长
     38 parameter id         = 16'h0000;               //分段标识
     39 parameter offset     = 16'h0000;               //偏移
     40 parameter ttl        = 16'h40;               //生存周期
     41 parameter protocol   = 8'h11;               //上层协议类型
     42 parameter src_ip     = 32'hc0_a8_00_02;      //源IP地址
     43 parameter dst_ip     = 32'hc0_a8_00_03;      //目的IP地址
     44 
     45 wire[15:0] ip_total_len;
     46 wire[15:0] udp_total_len;
     47 assign ip_total_len = data_total_len + 16'd28;
     48 assign udp_total_len = data_total_len + 16'd8;
     49 
     50 wire[31:0] CRC_Result;
     51 reg [7:0] lsm_cnt;           //序列机计数器,本以太网帧发送系统使用线性序列机方式设计
     52 wire CRC_EN;
     53 assign CRC_EN = (lsm_cnt >= 17 && lsm_cnt <= 144);
     54 
     55 crc32_d4 u0(
     56   .Clk(mii_tx_clk),
     57   .Rst_n(rst_n), 
     58   .Data(mii_tx_data), 
     59   .Enable(CRC_EN),
     60   .Initialize(~mii_tx_en),
     61   .Crc(), 
     62   .CrcError(),
     63   .Crc_eth(CRC_Result)
     64  );
     65 
     66 wire [31:0]sum;
     67 wire [15:0] ip_checksum;
     68 assign sum = {ver,hdr_len,tos} + ip_total_len + id + offset + {ttl,protocol} + src_ip[31:16]+ src_ip[15:0] + dst_ip[31:16] + dst_ip[15:0];
     69 
     70 assign ip_checksum = ~(sum[31:16] + sum[15:0]);
     71 
     72 wire tx_go;                // 使能发送
     73 
     74 reg en_tx;                   //内部的数据帧发送使能信号,高电平时将数据通过MII接口送出
     75 
     76 reg [28:0]cnt;  //发送间隔计数器
     77 always@(posedge mii_tx_clk or negedge rst_n)
     78   if(!rst_n)
     79      cnt <= 28'd0;
     80   else if(cnt == 28'd1000)  // 35000000
     81      cnt <= 28'd0;
     82   else
     83     cnt <= cnt + 1'b1;
     84     
     85 //每671ms启动一次发送数据    
     86 assign tx_go = (cnt == 28'd1000) ? 1'b1 : 1'b0;  // 35000000
     87 
     88 //根据发送启动信号产生内部发送使能信号
     89 always@(posedge mii_tx_clk or negedge rst_n) 
     90   if(!rst_n)
     91      en_tx <= 1'd0;
     92   else if(tx_go)
     93      en_tx <= 1'd1;
     94   else if(lsm_cnt >= 153)      //一帧数据发送完成,清零发送使能信号
     95      en_tx <= 1'd0;
     96 
     97 always@(posedge mii_tx_clk or negedge rst_n) //主序列机计数器
     98   if(!rst_n)
     99      lsm_cnt <= 8'd0;
    100   else if(en_tx) begin
    101     if(lsm_cnt == 8'd153)
    102        lsm_cnt <= 8'd0;
    103      else
    104        lsm_cnt <= lsm_cnt + 1'b1;
    105   end
    106   else
    107      lsm_cnt <= 8'd0;    
    108 
    109 always@(*) begin
    110     case(lsm_cnt)
    111        1: mii_tx_data <= 4'h5;  // 前导码 + 分隔符的一个5
    112         2: mii_tx_data <= 4'h5;
    113         3: mii_tx_data <= 4'h5;
    114         4: mii_tx_data <= 4'h5;
    115         5: mii_tx_data <= 4'h5;
    116         6: mii_tx_data <= 4'h5;
    117         7: mii_tx_data <= 4'h5;
    118         8: mii_tx_data <= 4'h5;
    119         9: mii_tx_data <= 4'h5;
    120         10:mii_tx_data <= 4'h5;
    121         11:mii_tx_data <= 4'h5;
    122         12:mii_tx_data <= 4'h5;
    123         13:mii_tx_data <= 4'h5;
    124         14:mii_tx_data <= 4'h5;
    125         15:mii_tx_data <= 4'h5;
    126             
    127         16: mii_tx_data <= 4'hd;  // 分隔符
    128         
    129       17: mii_tx_data <= des_mac[43:40];  // 目的MAC地址,先发高八位中的低四位 48'c4_54_44_97_c5_d7
    130         18: mii_tx_data <= des_mac[47:44];
    131         19: mii_tx_data <= des_mac[35:32];
    132         20: mii_tx_data <= des_mac[39:36];
    133         21: mii_tx_data <= des_mac[27:24];
    134         22: mii_tx_data <= des_mac[31:28];
    135         23: mii_tx_data <= des_mac[19:16];
    136         24: mii_tx_data <= des_mac[23:20];
    137         25: mii_tx_data <= des_mac[11:8];
    138         26: mii_tx_data <= des_mac[15:12];
    139         27: mii_tx_data <= des_mac[3:0];
    140         28: mii_tx_data <= des_mac[7:4];    
    141     
    142                   
    143         29: mii_tx_data <= src_mac[43:40];// 0  //源MAC地址 48'h00_0a_35_01_fe_c0
    144         30: mii_tx_data <= src_mac[47:44];// 0
    145         31: mii_tx_data <= src_mac[35:32];// a
    146         32: mii_tx_data <= src_mac[39:36];// 0
    147         33: mii_tx_data <= src_mac[27:24];// 5
    148         34: mii_tx_data <= src_mac[31:28];// 3
    149         35: mii_tx_data <= src_mac[19:16];// 1
    150         36: mii_tx_data <= src_mac[23:20];// 0
    151         37: mii_tx_data <= src_mac[11:8]; // e
    152         38: mii_tx_data <= src_mac[15:12];// f
    153         39: mii_tx_data <= src_mac[3:0]; // 0
    154         40: mii_tx_data <= src_mac[7:4];    // c
    155                 
    156         41: mii_tx_data <= type_length[11:8];  //以太网帧类型/长度,0x0800
    157         42: mii_tx_data <= type_length[15:12];
    158         43: mii_tx_data <= type_length[3:0];
    159         44: mii_tx_data <= type_length[7:4];
    160         
    161         45: mii_tx_data =    4'h5;  // IP首部长度
    162         46: mii_tx_data =    4'h4;  // IPv4协议
    163         
    164         47: mii_tx_data =    4'h0;  // 服务类型
    165         48: mii_tx_data =    4'h0;
    166         
    167         49: mii_tx_data =    ip_total_len[11:8];   // IP数据报总长度(IP报头+数据)
    168         50: mii_tx_data =    ip_total_len[15:12];
    169         51: mii_tx_data =    ip_total_len[3:0];
    170         52: mii_tx_data =    ip_total_len[7:4];
    171         
    172         53: mii_tx_data =    4'h0;  // 数据包标识
    173         54: mii_tx_data =    4'h0;
    174         55: mii_tx_data =    4'h0;
    175         56: mii_tx_data =    4'h0;
    176         
    177         57: mii_tx_data =    4'h0;  // 标识+分段偏移
    178         58: mii_tx_data =    4'h0;
    179         59: mii_tx_data =    4'h0;
    180         60: mii_tx_data =    4'h0;
    181         
    182         61: mii_tx_data =    4'h0;  // 生存时间
    183         62: mii_tx_data =    4'h4;
    184         
    185         63: mii_tx_data =    4'h1;  // 数据报类型 17: UDP
    186         64: mii_tx_data =    4'h1;
    187         
    188         65: mii_tx_data =    ip_checksum[11:8];  // IP报头校验和 使用自动IP和校验逻辑生成的校验和值
    189         66: mii_tx_data =    ip_checksum[15:12];
    190         67: mii_tx_data =    ip_checksum[3:0];
    191         68: mii_tx_data =    ip_checksum[7:4];
    192         
    193         //sender ip : 192.168.0.2
    194         69: mii_tx_data =    4'h0; // 192
    195         70: mii_tx_data =    4'hc;
    196         
    197         71: mii_tx_data =    4'h8; // 168
    198         72: mii_tx_data =    4'ha;
    199         
    200         73: mii_tx_data =    4'h0; // 0
    201         74: mii_tx_data =    4'h0;
    202         
    203         75: mii_tx_data =    4'h2;
    204         76: mii_tx_data =    4'h0; // 2
    205         
    206         77: mii_tx_data =    4'h0;  // 目的192.168.0.3
    207         78: mii_tx_data =    4'hc;
    208         
    209         79: mii_tx_data =    4'h8;
    210         80: mii_tx_data =    4'ha;
    211         
    212         81: mii_tx_data =    4'h0;   
    213         82: mii_tx_data =    4'h0;
    214 
    215       83: mii_tx_data = 4'h3;
    216       84: mii_tx_data = 4'h0;        
    217         
    218         85: mii_tx_data =    src_port[11:8];    // 源端口号5000(0x1388)
    219         86: mii_tx_data =    src_port[15:12];
    220         87: mii_tx_data =    src_port[3:0];  
    221         88: mii_tx_data =    src_port[7:4];
    222         
    223         89: mii_tx_data =    des_port[11:8];    // 目的端口号
    224         90: mii_tx_data =    des_port[15:12];  
    225         91: mii_tx_data =    des_port[3:0];  
    226         92: mii_tx_data =    des_port[7:4];
    227         
    228         93: mii_tx_data =    udp_total_len[11:8];  // UDP数据报总长度(UDP报头+数据)
    229         94: mii_tx_data =    udp_total_len[15:12]; 
    230         95: mii_tx_data =    udp_total_len[3:0];
    231         96: mii_tx_data =    udp_total_len[7:4];
    232         
    233         97: mii_tx_data =    4'h0;  // UDP报头校验和  忽略
    234         98: mii_tx_data =    4'h0;
    235         99: mii_tx_data =    4'h0;  
    236         100: mii_tx_data = 4'h0;
    237         
    238         101: mii_tx_data = 4'h8;   // H        // 用户数据:Hello, welcom to FPGA!
    239         102: mii_tx_data = 4'h4;
    240         
    241         103: mii_tx_data = 4'h5;  // e
    242         104: mii_tx_data = 4'h6;
    243         
    244         105: mii_tx_data = 4'hc;  // l
    245         106: mii_tx_data = 4'h6;
    246         
    247         107: mii_tx_data = 4'hc;  // l
    248         108: mii_tx_data = 4'h6;
    249         
    250         109: mii_tx_data = 4'hf;  // o
    251         110: mii_tx_data = 4'h6;
    252         
    253         111: mii_tx_data = 4'hc;  // ,
    254         112: mii_tx_data = 4'h2;
    255         
    256         113: mii_tx_data = 4'h7;  // W
    257         114: mii_tx_data = 4'h7;
    258         
    259         115: mii_tx_data = 4'h5;  // e
    260         116: mii_tx_data = 4'h6;
    261         
    262         117: mii_tx_data = 4'hc;  // l
    263         118: mii_tx_data = 4'h6;
    264         
    265         119: mii_tx_data = 4'h3;  // c
    266         120: mii_tx_data = 4'h6;  
    267         
    268         121: mii_tx_data = 4'hf;  // o
    269         122: mii_tx_data = 4'h6;
    270         
    271         123: mii_tx_data = 4'hd;  // m
    272         124: mii_tx_data = 4'h6;
    273         
    274         125: mii_tx_data = 4'h5;  // e
    275         126: mii_tx_data = 4'h6;
    276         
    277         127: mii_tx_data = 4'h0;  // 
    278         128: mii_tx_data = 4'h2;
    279         
    280         129: mii_tx_data = 4'h4;  // t
    281         130: mii_tx_data = 4'h7;
    282         
    283         131: mii_tx_data = 4'hf;  // o
    284         132: mii_tx_data = 4'h6;
    285         
    286         133: mii_tx_data = 4'h0;  // 
    287         134: mii_tx_data = 4'h2;
    288         
    289         135: mii_tx_data = 4'h6;  // F
    290         136: mii_tx_data = 4'h4;
    291         
    292         137: mii_tx_data = 4'h0;  // P
    293         138: mii_tx_data = 4'h5;
    294         
    295         139: mii_tx_data = 4'h7;  // G
    296         140: mii_tx_data = 4'h4;
    297         
    298         141: mii_tx_data = 4'h1;  // A
    299         142: mii_tx_data = 4'h4;
    300         
    301         143: mii_tx_data = 4'h1;  // !
    302         144: mii_tx_data = 4'h2;
    303         
    304         145: mii_tx_data <= CRC_Result[27:24];  //发送CRC 校验结果
    305         146: mii_tx_data <= CRC_Result[31:28];
    306         147: mii_tx_data <= CRC_Result[19:16];
    307         148: mii_tx_data <= CRC_Result[23:20];
    308         149: mii_tx_data <= CRC_Result[11:8];
    309         150: mii_tx_data <= CRC_Result[15:12];
    310         151: mii_tx_data <= CRC_Result[3:0];
    311         152: mii_tx_data <= CRC_Result[7:4];
    312 
    313         153: mii_tx_data <= 4'd0;
    314         default: mii_tx_data <= 4'd0;
    315      endcase
    316   end
    317 
    318 assign mii_tx_en = ((lsm_cnt >= 1) && (lsm_cnt <= 153)) ? 1'b1 : 1'b0;
    319 
    320 endmodule
    321     
    View Code
     1 `timescale 1ns/1ns
     2 module crc32_d4 (Clk, Rst_n, Data, Enable, Initialize, Crc, CrcError, Crc_eth);
     3 
     4 
     5 parameter Tp = 1;
     6 
     7 input Clk;
     8 input Rst_n;
     9 input [0:3] Data;
    10 input Enable;
    11 input Initialize;
    12 
    13 output [31:0] Crc;
    14 output [31:0] Crc_eth;
    15 
    16 output CrcError;
    17 
    18 reg  [31:0] Crc;
    19 
    20 wire [31:0] CrcNext;
    21 
    22 assign CrcNext[0] = Enable & (Data[0] ^ Crc[28]); 
    23 assign CrcNext[1] = Enable & (Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29]); 
    24 assign CrcNext[2] = Enable & (Data[2] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[30]); 
    25 assign CrcNext[3] = Enable & (Data[3] ^ Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30] ^ Crc[31]); 
    26 assign CrcNext[4] = (Enable & (Data[3] ^ Data[2] ^ Data[0] ^ Crc[28] ^ Crc[30] ^ Crc[31])) ^ Crc[0]; 
    27 assign CrcNext[5] = (Enable & (Data[3] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[31])) ^ Crc[1]; 
    28 assign CrcNext[6] = (Enable & (Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30])) ^ Crc[ 2]; 
    29 assign CrcNext[7] = (Enable & (Data[3] ^ Data[2] ^ Data[0] ^ Crc[28] ^ Crc[30] ^ Crc[31])) ^ Crc[3]; 
    30 assign CrcNext[8] = (Enable & (Data[3] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[31])) ^ Crc[4]; 
    31 assign CrcNext[9] = (Enable & (Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30])) ^ Crc[5]; 
    32 assign CrcNext[10] = (Enable & (Data[3] ^ Data[2] ^ Data[0] ^ Crc[28] ^ Crc[30] ^ Crc[31])) ^ Crc[6]; 
    33 assign CrcNext[11] = (Enable & (Data[3] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[31])) ^ Crc[7]; 
    34 assign CrcNext[12] = (Enable & (Data[2] ^ Data[1] ^ Data[0] ^ Crc[28] ^ Crc[29] ^ Crc[30])) ^ Crc[8]; 
    35 assign CrcNext[13] = (Enable & (Data[3] ^ Data[2] ^ Data[1] ^ Crc[29] ^ Crc[30] ^ Crc[31])) ^ Crc[9]; 
    36 assign CrcNext[14] = (Enable & (Data[3] ^ Data[2] ^ Crc[30] ^ Crc[31])) ^ Crc[10]; 
    37 assign CrcNext[15] = (Enable & (Data[3] ^ Crc[31])) ^ Crc[11]; 
    38 assign CrcNext[16] = (Enable & (Data[0] ^ Crc[28])) ^ Crc[12]; 
    39 assign CrcNext[17] = (Enable & (Data[1] ^ Crc[29])) ^ Crc[13]; 
    40 assign CrcNext[18] = (Enable & (Data[2] ^ Crc[30])) ^ Crc[14]; 
    41 assign CrcNext[19] = (Enable & (Data[3] ^ Crc[31])) ^ Crc[15]; 
    42 assign CrcNext[20] = Crc[16]; 
    43 assign CrcNext[21] = Crc[17]; 
    44 assign CrcNext[22] = (Enable & (Data[0] ^ Crc[28])) ^ Crc[18]; 
    45 assign CrcNext[23] = (Enable & (Data[1] ^ Data[0] ^ Crc[29] ^ Crc[28])) ^ Crc[19]; 
    46 assign CrcNext[24] = (Enable & (Data[2] ^ Data[1] ^ Crc[30] ^ Crc[29])) ^ Crc[20]; 
    47 assign CrcNext[25] = (Enable & (Data[3] ^ Data[2] ^ Crc[31] ^ Crc[30])) ^ Crc[21]; 
    48 assign CrcNext[26] = (Enable & (Data[3] ^ Data[0] ^ Crc[31] ^ Crc[28])) ^ Crc[22]; 
    49 assign CrcNext[27] = (Enable & (Data[1] ^ Crc[29])) ^ Crc[23]; 
    50 assign CrcNext[28] = (Enable & (Data[2] ^ Crc[30])) ^ Crc[24]; 
    51 assign CrcNext[29] = (Enable & (Data[3] ^ Crc[31])) ^ Crc[25]; 
    52 assign CrcNext[30] = Crc[26]; 
    53 assign CrcNext[31] = Crc[27]; 
    54 
    55 
    56 always @ (posedge Clk or negedge Rst_n)
    57 begin
    58   if (!Rst_n)
    59     Crc <= #1 32'hffffffff;
    60   else
    61   if(Initialize)
    62     Crc <= #Tp 32'hffffffff;
    63   else if(Enable)
    64     Crc <= #Tp CrcNext;
    65 end
    66 
    67 assign Crc_eth = ~{
    68                         CrcNext[28], CrcNext[29], CrcNext[30], CrcNext[31],
    69                         Crc[24], Crc[25], Crc[26], Crc[27],
    70                         Crc[20], Crc[21], Crc[22], Crc[23],
    71                         Crc[16], Crc[17], Crc[18], Crc[19],
    72                         Crc[12], Crc[13], Crc[14], Crc[15],
    73                         Crc[ 8], Crc[ 9], Crc[10], Crc[11],
    74                         Crc[ 4], Crc[ 5], Crc[ 6], Crc[ 7],
    75                         Crc[ 0], Crc[ 1], Crc[ 2], Crc[ 3]};
    76 
    77 
    78 assign CrcError = Crc[31:0] != 32'hc704dd7b;  // CRC not equal to magic number
    79 
    80 endmodule
    View Code

    仿真代码:

     1 `timescale 1ns/1ps
     2 module udp_test_tb;
     3   reg rst_n;
     4   reg  mii_tx_clk;           //MII接口发送时钟,由PHY芯片产生,25MHz
     5   wire mii_tx_en;           //MII接口发送数据使能信号,高电平有效
     6   wire mii_tx_er;           //发送错误,用以破坏数据包发送
     7   wire [3:0]mii_tx_data;   //MII接口发送数据线,FPGA通过该数据线将需要发送的数据依次送给PHY芯片
     8   wire phy_rst_n;     
     9   
    10 udp_test u0(
    11  .rst_n(rst_n),
    12      
    13  .mii_tx_clk(mii_tx_clk),
    14  .mii_tx_en(mii_tx_en),
    15  .mii_tx_er(mii_tx_er),
    16  .mii_tx_data(mii_tx_data),
    17  
    18  .phy_rst_n(phy_rst_n)
    19 );
    20 
    21 initial
    22   mii_tx_clk = 1'b0;
    23   always #20 mii_tx_clk = ~mii_tx_clk;
    24   
    25 initial
    26   begin
    27     rst_n = 1'b0;
    28      #100;
    29      rst_n = 1'b1;
    30      
    31      #100000;
    32      $stop;
    33   end
    34 endmodule
    View Code

    注:代码设计参考小梅哥的设计思路

     

     

  • 相关阅读:
    修改VS中的附加依赖项的继承值
    cocos2dx的addChild接口设计
    svn cleanup失败解决方法
    vi显示中文乱码
    CentOS 7.4 shell 不显示当前用户和路径的问题
    生产工具的差距导致的生产力(生产效率)的差距
    GPU的历史:从固定管线到可编程管线再到通用计算平台
    聊Java中的任务调度的实现方法及比较
    Spring Boot 揭秘与实战之RabbitMQ
    一个让Java事半功倍的反射库
  • 原文地址:https://www.cnblogs.com/571328401-/p/12686528.html
Copyright © 2020-2023  润新知