计算机网络 #
一、层级结构与对应协议 #
层级结构:
七层模型(OSI 七层模型):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。


应用层常用网络端口 #
常用网络端口与解释:

三次握手 #
- 第一次握手(客户端 → 服务端:SYN 报文) SYN=1,不允许携带任何数据。 协议规定:携带 SYN 标志的报文不能携带载荷数据,同时为了防止 SYN 洪水攻击、恶意占用服务器资源。
- 第二次握手(服务端 → 客户端:SYN+ACK 报文) SYN=1、ACK=1,同样不能携带数据。 只要 SYN 置 1,就不允许带业务数据。
- 第三次握手(客户端 → 服务端: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 驱动等)

lwip220,配置LWIP协议,确保lwip_tcp、lwip_udp、lwip_no_sys_no_timers为True,点击regerate BSP,重新生成BSP

Build验证是否添加BSP成功

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(ð_netif, &ipaddr, &netmask, &gw,
mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR)) {
xil_printf("xemac_add failed!\r\n");
return -1;
}
netif_set_default(ð_netif);
netif_set_up(ð_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(ð_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的配置中将速率从自动检测改为支持的的最大速率

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("程序退出")