跳过正文
  1. 文章列表/

计算机网络

·2182 字·5 分钟·
RayChaux
作者
RayChaux

计算机网络
#

一、层级结构与对应协议
#

层级结构: 七层模型(OSI 七层模型):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

alt text
四层模型(TCP/IP 四层模型):应用层、传输层、网络层、数据链路层。
alt text

应用层常用网络端口
#

常用网络端口与解释:

alt text

三次握手
#

  1. 第一次握手(客户端 → 服务端:SYN 报文) SYN=1,不允许携带任何数据。 协议规定:携带 SYN 标志的报文不能携带载荷数据,同时为了防止 SYN 洪水攻击、恶意占用服务器资源。
  2. 第二次握手(服务端 → 客户端:SYN+ACK 报文) SYN=1、ACK=1,同样不能携带数据。 只要 SYN 置 1,就不允许带业务数据。
  3. 第三次握手(客户端 → 服务端:ACK 报文) ACK=1、SYN=0,可以携带应用层数据。 此时逻辑连接已完成,客户端可直接捎带业务数据,省去单独发一次数据报文,提升传输效率。

嵌入式轻量化协议:LWIP
#

Light weight IP(LWIP)轻量化的 TCP/IP 协议,是瑞典计算机科学院(SICS)的 Adam Dunkels 开发的一个小型开源的 TCP/IP 协议栈。 LWIP 的设计初衷是:用少量的资源消耗(RAM)实现一个较为完整的 TCP/IP 协议栈, 在保持 TCP 协议主要功能的基础上减少对 RAM 的占用。

特性
#

附录:项目参考
#

项目一:RK3588通过以太网与与ZYNQ 7010通信
#

硬件平台: 正点原子RK3588开发板、ALINX-ZYNQ-7010开发板、网线直连 RK3588连接热点,与FPGA网线直连 软件平台: MobaXterm,Vivado 2025.2 & Vitis 2025.2

1. 配置RK3588
#

1.1 确认 RK3588 的有线网口

ip addr # 查看网卡信息
ip link set eth0 up # 启动网卡

1.2 配置RK3588的IP地址 RK3588固定的 IP 和子网掩码必须和 ZYNQ 同网段(192.168.2.x/24)

# 临时配置,重启后失效,适合测试
ip addr add 192.168.2.100/24 dev eth0
# 永久生效,用cat写配置文件
cat > /etc/network/interfaces << EOF
auto eth0
iface eth0 inet static
    address 192.168.2.100
    netmask 255.255.255.0
EOF
# 重启网络服务生效
/etc/init.d/S40network restart
# 测试:查看网卡状态(确认eth0已启用且IP正确)
ip addr
# 出现以下类似输出
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    inet 192.168.2.100/24 brd 192.168.2.255 scope global eth0

2. 配置ZYNQ
#

2.1 在Vivado添加Block Design,生成.xsa文件 2.2 在Vitis中导入.xsa文件,创建为Platform,选择裸机系统standalone 2.3 在Vitis中创建Application 工程,选择Platform为2.2中创建的Platform,进入Platform的项目设置,选中standalone_ps7_cortexa9_0下的Board Support Package,勾选lwip220,添加LWIP库 Tips:zynq_fsbl为First Stage Boot Loader(第一阶段引导加载程序)的BSP,standalone_ps7_cortexa9_0才为应用提供运行环境,包括 LWIP 库、UART 驱动等)

alt text
展开BSP,点击lwip220,配置LWIP协议,确保lwip_tcp、lwip_udp、lwip_no_sys_no_timers为True,点击regerate BSP,重新生成BSP
alt text
点击左下角的Build验证是否添加BSP成功
alt text

2.4 添加main.c文件:

#include <stdio.h>
#include <string.h>
#include "xparameters.h"
#include "xil_printf.h"
#include "lwip/init.h"
#include "lwip/netif.h"
#include "lwip/udp.h"
#include "netif/xadapter.h"
#include "xil_cache.h"

// -------------------------- 配置参数(和RK3588对应修改) --------------------------
#define UDP_PORT        5000        // 通信端口,两边要一致
#define ZYNQ_IP         "192.168.2.101"     // ZYNQ的IP地址
#define ZYNQ_NETMASK    "255.255.255.0"     // 子网掩码
#define ZYNQ_GW         "192.168.2.1"  // 网关可以不填,填路由器IP即可
#define MAC_ADDR        {0x00,0x0A,0x35,0x00,0x01,0x02} // MAC地址,可自定义

// -------------------------- 全局变量 --------------------------
static struct netif eth_netif;
static struct udp_pcb *udp_pcb;
unsigned char mac_ethernet_address[] = MAC_ADDR;

// -------------------------- UDP接收回调函数(核心逻辑) --------------------------
void udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p,
                       const ip_addr_t *addr, u16_t port)
{
    if (p == NULL) return;

    // 打印收到的数据
    xil_printf("Recv from %d.%d.%d.%d:%d: %s\r\n",
               ip4_addr1(addr), ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr),
               port, (char*)p->payload);

    // 回显数据给RK3588
    udp_sendto(pcb, p, addr, port);

    pbuf_free(p); // 释放pbuf,防止内存泄漏
}

// -------------------------- LWIP和以太网初始化 --------------------------
int lwip_eth_init(void)
{
    err_t err;
    ip_addr_t ipaddr, netmask, gw;

    // 解析IP地址
    ipaddr_aton(ZYNQ_IP, &ipaddr);
    ipaddr_aton(ZYNQ_NETMASK, &netmask);
    ipaddr_aton(ZYNQ_GW, &gw);

    // 初始化LWIP协议栈
    lwip_init();

    // 添加以太网接口(
    if (!xemac_add(&eth_netif, &ipaddr, &netmask, &gw,
                   mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR)) {
        xil_printf("xemac_add failed!\r\n");
        return -1;
    }

    netif_set_default(&eth_netif);
    netif_set_up(&eth_netif); // 启动网口

    // 创建UDP控制块
    udp_pcb = udp_new();
    if (udp_pcb == NULL) {
        xil_printf("udp_new failed!\r\n");
        return -1;
    }

    // 绑定本地端口
    err = udp_bind(udp_pcb, IP_ADDR_ANY, UDP_PORT);
    if (err != ERR_OK) {
        xil_printf("udp_bind failed, err=%d\r\n", err);
        udp_remove(udp_pcb);
        return -1;
    }

    // 注册接收回调函数
    udp_recv(udp_pcb, udp_recv_callback, NULL);
    xil_printf("UDP Server running on %s:%d\r\n", ZYNQ_IP, UDP_PORT);

    return 0;
}

// -------------------------- 主函数 --------------------------
int main(void)
{
    xil_printf("===== Program Started =====\r\n");  // 串口输出测试代码
    Xil_DCacheEnable(); // 开启数据缓存

    // 初始化LWIP和以太网
    if (lwip_eth_init() != 0) {
        xil_printf("LWIP init failed!\r\n");
        return -1;
    }

    // 主循环:处理网络数据
    while (1) {
        xemacif_input(&eth_netif); // 必须调用,否则网络数据无法处理
    }

    Xil_DCacheDisable();
    return 0;
}

2.5 build and run and debug 在控制台的debug console中可以看到打印的信息来debug 可能错误1:传输速率协商失败

Auto negotiation error 
Phy setup error : link_speed invalid
Phy setup failure init_emacps 

错误原因: 硬件的PHY芯片不支持自动协商,设置为自动检测时,表示由物理层自动协商链路速度,lwIP据此配置TEMAC/GigE,某些PHY可能不支持自动检测,此时这个值必须设置正确。 解决方法: 在lwip的配置中将速率从自动检测改为支持的的最大速率

alt text

3.检测通信
#

ping 192.168.2.101 -c 4
# 成功显示
PING 192.168.2.101 (192.168.2.101) 56(84) bytes of data.
64 bytes from 192.168.2.101: icmp_seq=1 ttl=255 time=0.510 ms
64 bytes from 192.168.2.101: icmp_seq=2 ttl=255 time=0.389 ms
64 bytes from 192.168.2.101: icmp_seq=3 ttl=255 time=0.392 ms
64 bytes from 192.168.2.101: icmp_seq=4 ttl=255 time=0.377 ms

--- 192.168.2.101 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3046ms

4.Python实现循环发送指令
#

import socket

ZYNQ_IP = "192.168.2.101"
ZYNQ_PORT = 5000
BUFFER_SIZE = 1024

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1.0)

print("=== RK3588 -> ZYNQ 指令控制客户端 ===")
print("支持指令: LED_ON / LED_OFF / PING / exit(退出)\n")

while True:
    cmd = input("请输入指令: ")
    if cmd.lower() == "exit":
        break

    # 发送指令到ZYNQ
    sock.sendto(cmd.encode("utf-8"), (ZYNQ_IP, ZYNQ_PORT))
    print(f"已发送指令: {cmd}")

    # 接收ZYNQ的处理结果
    try:
        resp, addr = sock.recvfrom(BUFFER_SIZE)
        print(f"ZYNQ回应: {resp.decode('utf-8')}\n")
    except socket.timeout:
        print("超时未收到回应,请检查ZYNQ端程序\n")

sock.close()
print("程序退出")
通过邮件回复