TCP/IP LWIP FPGA 笔记

参考资料:

正点原子

LwIP 之 网络接口 netif(ethernetif.c、netif.c)-CSDN博客

IPv4/IPv6、DHCP、网关、路由_ipv6有网关的概念吗-CSDN博客

TCP/IP

        TCP/IP 协议中文名为传输控制协议/因特网互联协议,又名网络通讯协议,是 Internet 最基本的协议、 Internet 国际互联网络的基础,由网络层的 IP 协议和传输层的 TCP 协议组成。TCP/IP 定义了电子设备如何 连入因特网,以及数据如何在它们之间传输的标准。协议采用了 4 层的层级结构,每一层都呼叫它的下一 层所提供的协议来完成自己的需求。

        通俗而言:TCP 负责发现传输的问题,一有问题就发出信号,要求重 新传输,直到所有数据安全正确地传输到目的地。而 IP 是给因特网的每一台联网设备规定一个地址。

        TCP/IP 协议不是 TCP 和 IP 这两个协议的合称,而是指因特网整个 TCP/IP 协议族。从协议分层模型方 面来讲,TCP/IP 由四个层次组成:网络接口层、网络层、传输层、应用层。OSI(Open System Interconnection) 是开放式系统互连参考模型,该模型将 TCP/IP 分为七层:物理层、数据链路层、网络层、传输层、会话层、 表示层和应用层。TCP/IP 模型与 OSI 模型对比如表 32.1.1 所示。

LWIP

        LWIP 是瑞典计算机科学院(SICS)的 Adam Dunkels 等开发的一个小型开源的 TCP/IP 协议栈,是 TCP/IP 的一种实现方式。LWIP 是轻量级 IP 协议,有无操作系统的支持都可以运行。

        LWIP 实现的重点是在保持 TCP协议主要功能的基础上减少对 RAM的占用,它只需十几KB的RAM和40K左右的ROM就可以运行, 这 使 LWIP 协议栈适合在低端的嵌入式系统中使用。关于 LWIP 的详细信息大家可以去 http://savannah.nongnu.org/projects/lwip/这个网站去查阅。

LWIP 的主要特性如下:

•IGMP 协议,用于网络组管理,可以实现多播数据的接收

•Internet 协议(IP),包括 IPv4 和 IPv6,支持 IP 分片与重装,包括通过多个网络接口的数据包转发

•用于网络维护和调试的 Internet 控制消息协议(ICMP)

•用户数据报协议(UDP)

•传输控制协议(TCP)拥塞控制,往返时间(RTT)估计,快速恢复和重传

•DNS,域名解析

•SNMP,简单网络管理协议

•动态主机配置协议(DHCP)

•以太网地址解析协议(ARP)

•AUTOIP,IP 地址自动配置

•PPP,点对点协议,支持 PPPoE

lwip212_v1_1

        lwip212_v1_1是一个基于开源 lwIP 库版本 2.1.2 构建的库(Vivado 2019.2 版本)。         lwip212_v1_1 库为 Ethernetlite(axi_ethernetlite)、TEMAC(axi_ethernet)以及千兆以太网控制器和 MAC (GigE)内核提供适配器。该库可以在 MicroBlaze、ARM Cortex-A9、ARM Cortex-A53 和 ARM Cortex-R5 处理器上运行。Ethernetlite 和 TEMAC 核心适用于 MicroBlaze 系统。千兆以太网控制器和 MAC(GigE)内核仅适用于 ARM Cortex-A9(MPSOC-7000 处理器设备)、ARM Cortex-A53 和 ARM Cortex-R5 系统(MPSOC UltraScale+ MPSoC)。

lwip212_v1_1 提供二种用户编程接口方式:

raw API 和 socket API

        Raw API:是为高性能和低内存开销而定制的。这种类型的 API 把网络协议栈和应用程序放在一个进程里,连接网络协议和应用程序的纽带是回调函数,回调函数实际上是一个普通的 C 函数。为了接收数据, 应用程序会首先向协议栈注册一个回调函数,当关联的连接有一个信息到达时,该回调函数就被协议栈调 用。这种实现方式即有优点也有缺点。

        优点是数据的接收和发送不会导致进程的切换,提供了最好的性能, 执行速度快,而且消耗的内存资源少;

        缺点是应用程序无法进行连续运算,因为网络协议的处理和运算是 在同一进程中完成的,二者无法并行发生。Raw API 是资源较少的嵌入式系统的首选方法,也是在没有操作系统的情况下运行 lwIP 时唯一可用的 API。

        Socket API:提供了一个基于 open-read-write-close 模块的 BSD socket-style 接口,需要操作系统,是标准的网络开发的API,正常情况下是基于进程方式开发的(LWIP裸机情况下没有进程的概念,没有优先级关系,只有嵌套关系)。

        此接口在性能和内存要求方面不如 Raw API 高效,不适用于小型嵌入式系统,但移植性更好,占的资源更多。

PS 的千兆以太网控制器

        在介绍 PS 的千兆以太网控制器之前,我们首先了解下 MAC 与 PHY 芯片及 GMII 与 RGMII 接口。

        以太网卡工作在 OSI 模型的最后两层,物理层和数据链路层,物理层定义了数据传送与接收所需要的 电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。

        物理层的芯 片称之为 PHY。此外 PHY 还提供了和对端设备连接的重要功能并通过 LED 灯显示出当前的连接的状态和 工作状态。

        当我们给网卡接入网线的时候,PHY 不断发出的脉冲信号检测到对端有设备,它们通过一套标准的语言交流,互相协商并确定连接速度、工作模式、是否采用流控等。

        通常情况下,协商的结果是两个设备中能同时支持的最大速度和最好的双工模式。

        这个技术被称为 AutoNegotiation,即自协商。

        数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接 口等功能。

        以太网卡中数据链路层的芯片称之为 MAC 控制器。

         MAC 控制器与 PHY 通过 MII(Medium Independent Interface)接口进行连接。MII 接口有很多类型, 千兆以太网多使用GMII(Gigabit Medium Independent Interface)或RGMII(Reduced Gigabit Media Independent Interface)接口进行连接。

例程模板:

/** Copyright (C) 2018 - 2019 Xilinx, Inc.* All rights reserved.** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice,*    this list of conditions and the following disclaimer.* 2. Redistributions in binary form must reproduce the above copyright notice,*    this list of conditions and the following disclaimer in the documentation*    and/or other materials provided with the distribution.* 3. The name of the author may not be used to endorse or promote products*    derived from this software without specific prior written permission.** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY* OF SUCH DAMAGE.**/#include <sleep.h>
#include "netif/xadapter.h"
#include "platform_config.h"
#include "xil_printf.h"
#include "lwip/init.h"
#include "lwip/inet.h"#if LWIP_IPV6==1
#include "lwip/ip6_addr.h"
#include "lwip/ip6.h"
#else#if LWIP_DHCP==1
#include "lwip/dhcp.h"
extern volatile int dhcp_timoutcntr;
err_t dhcp_start(struct netif *netif);
#endif
#define DEFAULT_IP_ADDRESS "192.168.1.10"
#define DEFAULT_IP_MASK "255.255.255.0"
#define DEFAULT_GW_ADDRESS "192.168.1.1"
#endif /* LWIP_IPV6 */#ifdef XPS_BOARD_ZCU102
#ifdef XPAR_XIICPS_0_DEVICE_ID
int IicPhyReset(void);
#endif
#endifstatic int complete_nw_thread;
static sys_thread_t main_thread_handle;void print_app_header();
void start_application();#define THREAD_STACKSIZE 1024struct netif server_netif;#if LWIP_IPV6==1
static void print_ipv6(char *msg, ip_addr_t *ip)
{print(msg);xil_printf(" %s\n\r", inet6_ntoa(*ip));
}
#elsestatic void print_ip(char *msg, ip_addr_t *ip)
{xil_printf(msg);xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),ip4_addr3(ip), ip4_addr4(ip));
}static void print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{print_ip("Board IP:       ", ip);print_ip("Netmask :       ", mask);print_ip("Gateway :       ", gw);
}static void assign_default_ip(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{int err;xil_printf("Configuring default IP %s \r\n", DEFAULT_IP_ADDRESS);err = inet_aton(DEFAULT_IP_ADDRESS, ip);if(!err)xil_printf("Invalid default IP address: %d\r\n", err);err = inet_aton(DEFAULT_IP_MASK, mask);if(!err)xil_printf("Invalid default IP MASK: %d\r\n", err);err = inet_aton(DEFAULT_GW_ADDRESS, gw);if(!err)xil_printf("Invalid default gateway address: %d\r\n", err);
}
#endif /* LWIP_IPV6 */void network_thread(void *p)
{
#if ((LWIP_IPV6==0) && (LWIP_DHCP==1))int mscnt = 0;
#endif/* the mac address of the board. this should be unique per board */u8_t mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };xil_printf("\n\r\n\r");xil_printf("-----lwIP Socket Mode TCP Server Application------\r\n");/* Add network interface to the netif_list, and set it as default */if (!xemac_add(&server_netif, NULL, NULL, NULL, mac_ethernet_address,PLATFORM_EMAC_BASEADDR)) {xil_printf("Error adding N/W interface\r\n");return;}#if LWIP_IPV6==1server_netif.ip6_autoconfig_enabled = 1;netif_create_ip6_linklocal_address(&server_netif, 1);netif_ip6_addr_set_state(&server_netif, 0, IP6_ADDR_VALID);print_ipv6("\n\rlink local IPv6 address is:",&server_netif.ip6_addr[0]);
#endif /* LWIP_IPV6 */netif_set_default(&server_netif);/* specify that the network if is up */netif_set_up(&server_netif);/* start packet receive thread - required for lwIP operation */sys_thread_new("xemacif_input_thread",(void(*)(void*))xemacif_input_thread, &server_netif,THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);complete_nw_thread = 1;/* Resume the main thread; auto-negotiation is completed */vTaskResume(main_thread_handle);#if ((LWIP_IPV6==0) && (LWIP_DHCP==1))dhcp_start(&server_netif);while (1) {vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);dhcp_fine_tmr();mscnt += DHCP_FINE_TIMER_MSECS;if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {dhcp_coarse_tmr();mscnt = 0;}}
#elsevTaskDelete(NULL);
#endif
}void main_thread(void *p)
{
#if ((LWIP_IPV6==0) && (LWIP_DHCP==1))int mscnt = 0;
#endif#ifdef XPS_BOARD_ZCU102IicPhyReset();
#endif/* initialize lwIP before calling sys_thread_new */lwip_init();/* any thread using lwIP should be created using sys_thread_new */sys_thread_new("nw_thread", network_thread, NULL,THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);/* Suspend Task until auto-negotiation is completed */if (!complete_nw_thread)vTaskSuspend(NULL);#if LWIP_IPV6==0
#if LWIP_DHCP==1while (1) {vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);if (server_netif.ip_addr.addr) {xil_printf("DHCP request success\r\n");break;}mscnt += DHCP_FINE_TIMER_MSECS;if (mscnt >= 10000) {xil_printf("ERROR: DHCP request timed out\r\n");assign_default_ip(&(server_netif.ip_addr),&(server_netif.netmask),&(server_netif.gw));break;}}#elseassign_default_ip(&(server_netif.ip_addr), &(server_netif.netmask),&(server_netif.gw));
#endifprint_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask),&(server_netif.gw));
#endif /* LWIP_IPV6 */xil_printf("\r\n");/* print all application headers */print_app_header();xil_printf("\r\n");/* start the application*/start_application();vTaskDelete(NULL);return;
}int main()
{main_thread_handle = sys_thread_new("main_thread", main_thread, 0,THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);vTaskStartScheduler();while(1);return 0;
}

进程:

/*------------------------------------------------ ---------------------------* 
* 例程:sys_thread_new 
*----------------- -------------------------------------------------- -----* 
* 描述: 
* 启动一个优先级为“prio”的新线程,该线程将在函数“thread()”中开始执行。 “arg”参数将作为参数传递给 thread() 函数。返回新 
* 线程的 id。 id 和优先级均取决于系统。
* 输入: 
* char *name:线程的名称。
* void (* thread)(void *arg):指向要运行的函数的指针。这个函数接受一个 void* 类型的参数。
* void *arg:传递给线程函数的参数。
* int stacksize:线程所需的堆栈大小(以字节为单位)。
* int prio:线程的优先级。
* 输出: 
* sys_thread_t -- 指向每个线程超时的指针。
*------------------------------------------------- --------------------------*/
/*---------------------------------------------------------------------------** Routine:  sys_thread_new*---------------------------------------------------------------------------** Description:*      Starts a new thread with priority "prio" that will begin its*      execution in the function "thread()". The "arg" argument will be*      passed as an argument to the thread() function. The id of the new*      thread is returned. Both the id and the priority are system*      dependent.* Inputs:*      char *name              -- Name of thread*      void (* thread)(void *arg) -- Pointer to function to run.*      void *arg               -- Argument passed into function*      int stacksize           -- Required stack amount in bytes*      int prio                -- Thread priority* Outputs:*      sys_thread_t            -- Pointer to per-thread timeouts.*---------------------------------------------------------------------------*/
sys_thread_t sys_thread_new( const char *pcName, 
void( *pxThread )( void *pvParameters ), 
void *pvArg, int iStackSize, int iPriority )
{
xTaskHandle xCreatedTask;
portBASE_TYPE xResult;
sys_thread_t xReturn;xResult = xTaskCreate( pxThread, ( const char * const) pcName, iStackSize, pvArg, iPriority, &xCreatedTask );if( xResult == pdPASS ){xReturn = xCreatedTask;}else{xReturn = NULL;}return xReturn;
}/** Prints an assertion messages and aborts execution.*/
void sys_assert( const char *pcMessage )
{(void) pcMessage;for (;;){}
}
/*-------------------------------------------------------------------------** End of File:  sys_arch.c*-------------------------------------------------------------------------*/

进程定义:

主进程

void main_thread(void *p)
{
#if ((LWIP_IPV6==0) && (LWIP_DHCP==1))int mscnt = 0;
#endif#ifdef XPS_BOARD_ZCU102IicPhyReset();
#endif/* initialize lwIP before calling sys_thread_new */lwip_init();/* any thread using lwIP should be created using sys_thread_new */sys_thread_new("nw_thread", network_thread, NULL,THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);/* Suspend Task until auto-negotiation is completed */if (!complete_nw_thread)vTaskSuspend(NULL);#if LWIP_IPV6==0
#if LWIP_DHCP==1while (1) {vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);if (server_netif.ip_addr.addr) {xil_printf("DHCP request success\r\n");break;}mscnt += DHCP_FINE_TIMER_MSECS;if (mscnt >= 10000) {xil_printf("ERROR: DHCP request timed out\r\n");assign_default_ip(&(server_netif.ip_addr),&(server_netif.netmask),&(server_netif.gw));break;}}#elseassign_default_ip(&(server_netif.ip_addr), &(server_netif.netmask),&(server_netif.gw));
#endifprint_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask),&(server_netif.gw));
#endif /* LWIP_IPV6 */xil_printf("\r\n");/* print all application headers */print_app_header();xil_printf("\r\n");/* start the application*/start_application();vTaskDelete(NULL);return;
}
  1. 如果启用了DHCP,定义一个计数器 mscnt

  2. 如果目标平台是 XPS_BOARD_ZCU102,则执行 IicPhyReset(),这可能是与PHY相关的初始化。

  3. 调用 lwip_init() 进行lwIP协议栈的初始化。

  4. 通过 sys_thread_new 创建一个名为 "nw_thread" 的新线程,该线程执行 network_thread 函数。这个函数主要用于网络接口的配置和启动lwIP协议栈中的相关功能。

  5. 在启动网络线程后,通过 vTaskSuspend(NULL) 暂停当前任务,直到网络线程完成。

  6. 如果启用了DHCP且未启用IPv6,进入一个循环,等待DHCP请求成功。如果超时,输出错误信息并分配默认的IP地址。

  7. 如果未启用IPv6,通过 assign_default_ip 分配默认的IP地址、子网掩码和网关。

  8. 打印网络配置信息。

  9. 调用 print_app_header() 打印应用程序的头部信息。

  10. 调用 start_application() 启动应用程序。

  11. 通过 vTaskDelete(NULL) 结束当前线程。

        总体而言,这段代码是一个lwIP网络应用程序的入口点,负责初始化lwIP协议栈、创建网络线程、进行网络配置和启动应用程序。在网络线程完成初始化后,主线程通过 vTaskSuspend 暂停,等待网络线程完成后继续执行。

子进程 :网络配置进程

LwIP 之 网络接口 netif(ethernetif.c、netif.c)-CSDN博客

struct netif
Generic data structure used for all lwIP network interfaces.
The following fields should be filled in by the initialization
function for the device driver: hwaddr_len, hwaddr[], mtu, flagshwaddr_len:表示硬件地址(MAC地址)的长度。hwaddr[]:表示硬件地址(MAC地址)的数组。mtu:表示最大传输单元(Maximum Transmission Unit),
即网络接口可以传输的最大数据包的大小。flags:表示网络接口的标志。这可以包括各种有关网络接口状态或特性的标志。这些字段的填充是在设备驱动程序的初始化函数中进行的,以确保网络接口能够正确地工作。
这是在lwIP协议栈中管理网络接口的基本信息的一种方式。
void network_thread(void *p)
{
#if ((LWIP_IPV6==0) && (LWIP_DHCP==1))int mscnt = 0;
#endif/* the mac address of the board. this should be unique per board */u8_t mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };xil_printf("\n\r\n\r");xil_printf("-----lwIP Socket Mode TCP Server Application------\r\n");/* struct netif *xemac_add(struct netif *netif, ip_addr_t *ipaddr, *  ip_addr_t *netmask, ip_addr_t *gw, *  unsigned char *mac_ethernet_address, UINTPTR mac_baseaddr) *//* 将网络接口添加到netif_list,并将其设置为默认*//* Add network interface to the netif_list, and set it as default */if (!xemac_add(&server_netif, NULL, NULL, NULL, mac_ethernet_address,PLATFORM_EMAC_BASEADDR)) {xil_printf("Error adding N/W interface\r\n");return;}#if LWIP_IPV6==1server_netif.ip6_autoconfig_enabled = 1;netif_create_ip6_linklocal_address(&server_netif, 1);netif_ip6_addr_set_state(&server_netif, 0, IP6_ADDR_VALID);print_ipv6("\n\rlink local IPv6 address is:",&server_netif.ip6_addr[0]);
#endif /* LWIP_IPV6 */netif_set_default(&server_netif);/* specify that the network if is up */netif_set_up(&server_netif);/* The input thread calls lwIP to process any received packets.* This thread waits until a packet is received (sem_rx_data_available), * and then calls xemacif_input which processes 1 packet at a time.*//* start packet receive thread - required for lwIP operation */sys_thread_new("xemacif_input_thread",(void(*)(void*))xemacif_input_thread, &server_netif,THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);complete_nw_thread = 1;/* Resume the main thread; auto-negotiation is completed */vTaskResume(main_thread_handle);#if ((LWIP_IPV6==0) && (LWIP_DHCP==1))dhcp_start(&server_netif);while (1) {vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);dhcp_fine_tmr();mscnt += DHCP_FINE_TIMER_MSECS;if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {dhcp_coarse_tmr();mscnt = 0;}}
#elsevTaskDelete(NULL);
#endif
}

  1. 定义了一个函数 network_thread,该函数接受一个 void* 类型的参数,通常用于线程传递。

  2. 初始化了一个以太网 MAC 地址 mac_ethernet_address

  3. 添加网络接口到 netif_list 中,并设置为默认接口。

  4. 如果启用了IPv6,配置IPv6地址。

  5. 将网络接口标记为 "up",表示网络接口已准备好接收和发送数据。

  6. 启动一个新的线程 xemacif_input_thread,用于处理接收到的网络数据包:监听EMAC;

  7. 标记网络线程已完成(complete_nw_thread = 1)。

  8. 恢复主线程的执行(vTaskResume(main_thread_handle))。

  9. 如果未启用IPv6且启用了DHCP,启动DHCP客户端并进入一个无限循环等待DHCP完成。

  10. 如果启用了IPv6或未启用DHCP,通过 vTaskDelete(NULL) 结束当前线程。

        总体而言,这段代码负责配置网络接口,启动lwIP协议栈的相关功能,包括处理接收到的数据包和启动DHCP客户端。在网络配置完成后,它通过 vTaskResume 恢复主线程的执行。

DHCP

        IPv4/IPv6、DHCP、网关、路由_ipv6有网关的概念吗-CSDN博客
        DHCP(Dynamic Host Configuration Protocol)是一种网络协议,用于自动分配IP地址和其他网络配置信息给计算机或设备。以下是DHCP的基本原理和功能:

        自动IP地址分配: DHCP允许计算机或设备在加入网络时自动获取IP地址,而无需手动配置。这有助于简化网络管理,特别是在大型网络中。

        配置信息分发: 除了IP地址外,DHCP还可以分配其他网络配置信息,包括子网掩码、网关、DNS服务器等。这使得设备能够在连接到网络时获取所有必要的配置信息。

        动态分配: DHCP支持动态IP地址分配,其中IP地址是从一个地址池中动态分配的,而不是静态分配给特定设备。这有助于更有效地管理IP地址资源。

        租约机制: DHCP分配的IP地址是有限期的,称为租约。设备在租约到期前可以续租,否则将释放该IP地址,返回到地址池中供其他设备使用。这有助于防止未使用的IP地址占用网络资源。

        减少配置错误: DHCP减少了手动配置IP地址和相关网络信息的可能性,从而降低了配置错误的风险。

        在上述代码中,DHCP被用于自动获取IP地址,并通过循环定期调用DHCP的定时器函数来处理DHCP过程。DHCP的执行过程会在后台自动完成,直到获取到有效的IP地址或超时。

LwIP 之 网络接口 netif(ethernetif.c、netif.c)-CSDN博客

 LwIP使用netif来描述一个硬件网络接口,但是由于网络接口是直接与硬件打交道的,硬件不同则处理可能不同,必须由用户提供最底层接口。

        LwIP的网络驱动有一定的模型,/src/netif/ethernetif.c文件即为底层接口的驱动的模版,用户为自己的网络设备实现驱动时应参照此模块。

        该文件中的函数通常为与硬件打交道的函数,当有数据接收的时候被调用,以使接收到的数据进入tcpip协议栈。
  简单来说,netif是LwIP抽象出来的各网络接口,协议栈可以使用多个不同的接口,而ethernetif则提供了netif访问硬件的各接口,每个不同的接口有不同的ethernetif

print_app_header

void print_app_header(void)
{xil_printf("TCP server listening on port %d\r\n",TCP_CONN_PORT);
#if LWIP_IPV6==1xil_printf("On Host: Run $iperf -V -c %s%%<interface> -i %d -t 300 -w 2M\r\n",inet6_ntoa(server_netif.ip6_addr[0]),INTERIM_REPORT_INTERVAL);
#elsexil_printf("On Host: Run $iperf -c %s -i %d -t 300 -w 2M\r\n",inet_ntoa(server_netif.ip_addr),INTERIM_REPORT_INTERVAL);
#endif /* LWIP_IPV6 */
}
  1. 使用 xil_printf 函数输出TCP服务器监听的端口号,通过 %d 显示 TCP_CONN_PORT 变量的值。

  2. 使用条件编译判断IPv6是否启用,如果启用,输出一条IPv6相关的命令提示,包括使用 iperf 工具进行测试的命令。其中,inet6_ntoa 函数用于将IPv6地址转换成可打印的字符串格式,并获取 server_netif 结构体中的第一个IPv6地址(server_netif.ip6_addr[0])。

  3. 如果未启用IPv6,输出一条IPv4相关的命令提示,同样包括使用 iperf 工具进行测试的命令。其中,inet_ntoa 函数用于将IPv4地址转换成可打印的字符串格式,并获取 server_netif 结构体中的IPv4地址(server_netif.ip_addr)。

        这样,该函数为用户提供了与TCP服务器通信的建议命令,方便用户在主机上运行相应的 iperf 命令进行性能测试。

start_application

1.启动Socket,失败则打印;

2.

void start_application(void)
{int sock, new_sd;
#if LWIP_IPV6==1struct sockaddr_in6 address, remote;
#elsestruct sockaddr_in address, remote;
#endif /* LWIP_IPV6 */int size;/* set up address to connect to */memset(&address, 0, sizeof(address));
#if LWIP_IPV6==1if ((sock = lwip_socket(AF_INET6, SOCK_STREAM, 0)) < 0) {xil_printf("TCP server: Error creating Socket\r\n");return;}address.sin6_family = AF_INET6;address.sin6_port = htons(TCP_CONN_PORT);address.sin6_len = sizeof(address);
#elseif ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0) {xil_printf("TCP server: Error creating Socket\r\n");return;}address.sin_family = AF_INET;address.sin_port = htons(TCP_CONN_PORT);address.sin_addr.s_addr = INADDR_ANY;
#endif /* LWIP_IPV6 */if (bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0) {xil_printf("TCP server: Unable to bind to port %d\r\n",TCP_CONN_PORT);close(sock);return;}if (listen(sock, 1) < 0) {xil_printf("TCP server: tcp_listen failed\r\n");close(sock);return;}size = sizeof(remote);while (1) {if ((new_sd = accept(sock, (struct sockaddr *)&remote,(socklen_t *)&size)) > 0)sys_thread_new("TCP_recv_perf thread",tcp_recv_perf_traffic, (void*)&new_sd,TCP_SERVER_THREAD_STACKSIZE,DEFAULT_THREAD_PRIO);}
}

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

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

相关文章

MySQL 安装配置 windows

一、下载 去官网MySQL :: MySQL Downloads 下载社区版 然后根据自己的系统选择 直接下载。 二、安装 点击安装程序 这边看样子缺少东西。 去这边下载 Latest supported Visual C Redistributable downloads | Microsoft Learn 然后再一次安装mysql 三、配置 安装完成后&a…

C++重新入门-C++基本语法

目录 1.C程序结构 2.C 中的分号 & 语句块 3.C 标识符 4.C 关键字 5.C 中的空格 1.C程序结构 C程序结构通常包括以下几个主要部分&#xff1a; 注释&#xff08;Comments&#xff09;&#xff1a; 注释是用来解释代码的文字&#xff0c;对于程序员而言是非常重要的。在…

记录关于node接收上传文件formData踩的坑

1.vue2使用插件formidable实现接收文件&#xff0c;首先接口不可以使用任何中间件&#xff0c;否则form.parse()方法不执行。 const express require(express) const multipart require(connect-multiparty); const testController require(../controller/testController)/…

WordPress SMTP发信避坑指南

前言 Clip_2024-01-31_19-46-18803285 10.5 KB 目前不少主题已经内置了SMTP发信功能&#xff0c;这是因为WordPress自带的mail()函数发信时基本无法发送。 但是在之前&#xff08;约2021年末&#xff09;貌似可以通过WordPress自带的函数发信&#xff0c;并且收信方提示由xxx代…

可以将linux docker容器中的文件拿出来吗?

当然可以。在Linux环境下&#xff0c;可以从Docker容器中将文件拿出来&#xff08;即复制到宿主机上&#xff09;&#xff0c;或者将宿主机的文件复制到Docker容器中。以下是两种常用方法&#xff1a; 方法1&#xff1a;使用 docker cp 命令 直接从命令行拷贝文件或目录&…

MySQL数据库安全加固方案

数据库版本:MySQL8.0.22 按照本安全加固方案进行的数据库加固,一般安全扫描工具扫描出来几乎无漏洞。 1.2 帐号安全 1.2.1 避免不同用户间共享帐号 参考以下步骤。 A. 创建用户。 mysql>CREATE USER ‘用户名’@‘用户 host’ IDENTIFIED BY ‘密码’; 执行以上命令可以…

Request Response 基础篇

Request & Response 在之前的博客中&#xff0c;初最初见到Request和Response对象&#xff0c;是在Servlet的Service方法的参数中&#xff0c;之前隐性地介绍过Request的作用是获取请求数据。通过获取的数据来进行进一步的逻辑处理&#xff0c;然后通过对Response来进行数…

C# Onnx yolov8 水表读数检测

目录 效果 模型信息 项目 代码 训练数据 下载 C# Onnx yolov8 水表读数检测 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-01-31T10:18:10.141465 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-…

c语言---访问越界之后死循环的原因

目录 死循环的概念环境题目代码运行结果对代码发生情况进行解释对i的地址和arr[12]地址一样的解释注意总结 死循环的概念 简单来说&#xff0c;死循环就是指无法靠自身的控制终止循环&#xff0c;在编程中&#xff0c;则是靠自身控制无法终止的程序。即在某一时刻&#xff0c;…

uniapp基于Android平台的校园生活服务交流论坛系统(二手,失物招领 -跑腿) 小程序hbuiderx

作为一款APP的校园论坛系统&#xff0c;面向的是大多数学者&#xff0c;软件的界面设计简洁清晰&#xff0c;用户可轻松掌握使用技巧。在调查之后&#xff0c;获得用户以下需求&#xff1a; &#xff08;1&#xff09;用户注册登录后&#xff0c;可进入系统解锁更多功能&#x…

Python中的Statsmodels库实际案例解析1:市场营销效果分析

在现代商业环境中,了解和评估市场营销活动的效果对于企业来说至关重要。它不仅帮助企业优化广告支出,还能够提高市场策略的整体效率。本文将通过一个实际案例,展示如何使用Python中的Statsmodels库来进行市场营销效果的分析。 写在开头 市场营销效果分析对于评估和优化广告…

【从零开始的rust web开发之路 四】rust语言tokio异步使用redis教程

文章目录 前言一、首先引入依赖二、创建redis客户端三、相关操作设置值mset设置多个key值设置含有过期时间的值如果key不存在才设置获取基本类型值删除一个键删除多个键判断键是否存在 如何使用json序列化导入相关依赖代码相关实例 总结 前言 使用rust写web&#xff0c;自然是…

Windows网络常用的11个命令,ping、tracert、arp、ipconfig、netstat、telnet等

1&#xff0e;ping命令 ping是个使用频率极高的实用程序&#xff0c;主要用于确定网络的连通性。ping能够以毫秒为单位显示延迟。如果应答时间短&#xff0c;表示数据报不必通过太多的路由器或网络&#xff0c;连接速度比较快。ping还能显示TTL&#xff08;Time To Live&#…

AspNet web api 和mvc 过滤器差异

最近在维护老项目。定义个拦截器记录接口日志。但是发现不生效 最后发现因为继承的 ApiController不是Controller 只能用 System.Web.Http下的拦截器生效。所以现在总结归纳一下 Web Api: System.Web.Http.Filters.ActionFilterAttribute 继承该类 Mvc: System.Web.Mvc.Ac…

客户端和服务端的简介

Client 和 Server 客户端&#xff08;Client&#xff09; 或称用户端&#xff0c;是指与服务器相对应&#xff0c;为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外&#xff0c;一般安装在客户机上&#xff0c;需要与服务端互相配合运行。例如&#xff1a;下载 Q…

ChatGPT炸裂了

优质内容&#xff1a;ChatGPT太炸裂了 hello&#xff0c;我是小索奇 很多人在使用ChatGPT时遇到了两个主要问题&#xff0c;导致他们觉得这个工具并没有带来太多实际价值。首先&#xff0c;许多人发现ChatGPT的回答缺乏深度&#xff0c;缺乏实用性。其次&#xff0c;一些人在使…

MySQL操作问题汇总

MySQL操作问题汇总 无法远程连接Ubuntu的MySQL 无法远程连接Ubuntu的MySQL 提示&#xff1a;MySQL默认只允许本地连接&#xff1a;localhost 解决&#xff1a; #1.修改配置文件 #/etc/mysql/mysql.conf.d/mysqld.cnf > cp /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/…

WebSocketServer依赖注入问题

WebSocketServer加入spring的bean管理 问题 @Component @ServerEndpoint("/webSocket/{topic}") @Slf4j public class WebSocketServer {@Autowiredprivate WsHandle wsHandle;} 前面使用@ServerEndpoint注册一个websocket服务端,然后发现wsHandle依赖注入失败,…

STM32GPIO输入(按键控制LED、光敏电阻控制蜂鸣器实例)

文章目录 一、介绍传感器模块介绍硬件电路c语言数据类型 二、实例按键控制LED接线图代码实现 光敏电阻控制蜂鸣器组装线路代码实现 相关函数解释 一、介绍 传感器模块介绍 硬件电路 上两种按下时为0&#xff0c;下两种按下时为1。 c语言数据类型 现在常用stdint头文件所定…

BeanDefinitionRegistry学习

Spring版本5.1.x 简介 在Spring框架中&#xff0c;BeanDefinitionRegistry是一个接口&#xff0c;它主要用于向注册表中注册BeanDefinition实例&#xff0c;完成注册的过程。该接口的主要方法是registerBeanDefinition&#xff0c;用于将一个BeanDefinition实例注册到注册表中…