STM32F4x7标准库移植LWIP

news2024/11/14 15:05:32

项目背景

使用GD芯片的我们,都会去参考ST的代码。可是呢,有一个很大的问题就是,ST早就提供HAL库了,而目前GD还只有标准库。在移植LWIP的时候,会有很多不便。

好在天无绝人之路,找到了一份ST的官方例程,是使用标准库来移植LWIP的。

参考资料

AN3966-Application note-LwIP TCPIP stack demonstration for STM32F4x7 microcontrollers.pdf

附上链接:

an3966-lwip-tcpip-stack-demonstration-for-stm32f4x7-microcontrollers-stmicroelectronics.pdf

  

配套代码包:

STSW-STM32070 - LwIP TCP/IP stack demonstration for STM32F4x7 microcontrollers (AN3966) - STMicroelectronics

代码结构

库代码

是标准库代码,版本V1.1.0,2013年的。

LWIP代码

版本是V1.4.1

例程代码

有两部分,无操作系统的,以及带FreeRTOS的。

关键代码

先解读不带OS的。

以 ...\Standalone\tcp_echo_server\工程为例。

关键代码分几个部分:

main()函数;

硬件外设配置;

lwip驱动;

应用层任务;

代码解读

main()函数

初始化

初始化部分,最主要的有3件事:

  ETH_BSP_Config();        // 配置GPIO、时钟、MAC、DMA

  LwIP_Init();                        // 协议栈初始化

  tcp_echoserver_init();        // 应用层任务初始化

主循环

主循环里的逻辑就很简单了,如果收到了以太网的报文,就处理数据包;

再调一个周期性的任务:LwIP_Periodic_Handle();

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured to 
       168 MHz, this is done through SystemInit() function which is called from
       startup file (startup_stm32f4xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f4xx.c file
     */

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

#ifdef SERIAL_DEBUG
  DebugComPort_Init();  
#endif

  /*Initialize LCD and Leds */ 
  LCD_LED_Init();
  
  /* configure ethernet (GPIOs, clocks, MAC, DMA) */
  ETH_BSP_Config();

  /* Initilaize the LwIP stack */
  LwIP_Init();
  
  /* tcp echo server Init */
  tcp_echoserver_init();
   
  /* Infinite loop */
  while (1)
  {  
    /* check if any packet received */
    if (ETH_CheckFrameReceived())
    { 
      /* process received ethernet packet*/
      LwIP_Pkt_Handle();
    }
    /* handle periodic timers for LwIP*/
    LwIP_Periodic_Handle(LocalTime);
  } 
}

外设配置

ETH_BSP_Config() -->ETH_GPIO_Config()

关键地方:配置MII模式还是RMII模式

  /* MII/RMII Media interface selection --------------------------------------*/
#ifdef MII_MODE /* Mode MII with STM324xx-EVAL  */

  SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII);

#elif defined RMII_MODE  /* Mode RMII with STM324xx-EVAL */

  SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);

#endif

配置网络接口:最主要的就是以太网初始化ETH_Init();

/**
  * @brief  Configures the Ethernet Interface
  * @param  None
  * @retval None
  */
static void ETH_MACDMA_Config(void)
{  
  /* Enable ETHERNET clock  */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx |
                        RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);

  /* Reset ETHERNET on AHB Bus */
  ETH_DeInit();

  /* Software reset */
  ETH_SoftwareReset();

  /* Wait for software reset */
  while (ETH_GetSoftwareResetStatus() == SET);

  /* ETHERNET Configuration --------------------------------------------------*/
  /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */
  ETH_StructInit(&ETH_InitStructure);

  /* Fill ETH_InitStructure parametrs */
  /*------------------------   MAC   -----------------------------------*/
  ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
//  ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Disable;
//  ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
//  ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;

  ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
  ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
  ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
  ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
  ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
  ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
  ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
  ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
#ifdef CHECKSUM_BY_HARDWARE
  ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;
#endif

  /*------------------------   DMA   -----------------------------------*/  
  
  /* When we use the Checksum offload feature, we need to enable the Store and Forward mode: 
  the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum, 
  if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
  ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;
  ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
  ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;

  ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;
  ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;
  ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
  ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;
  ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;
  ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;
  ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
  ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;

  /* Configure Ethernet */
  EthStatus = ETH_Init(&ETH_InitStructure, DP83848_PHY_ADDRESS);
}

协议栈初始化

LwIP_Init()函数,在netconf.c文件里。

删除DHCP和LCD显示后的LwIP_Init()函数代码如下:

/**
* @brief  Initializes the lwIP stack
* @param  None
* @retval None
*/
void LwIP_Init(void)
{
  struct ip_addr ipaddr;
  struct ip_addr netmask;
  struct ip_addr gw;

  /* Initializes the dynamic memory heap defined by MEM_SIZE.*/
  mem_init();
  
  /* Initializes the memory pools defined by MEMP_NUM_x.*/
  memp_init();
  
  IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
  IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
  IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);

  /* - netif_add(struct netif *netif, struct ip_addr *ipaddr,
  struct ip_addr *netmask, struct ip_addr *gw,
  void *state, err_t (* init)(struct netif *netif),
  err_t (* input)(struct pbuf *p, struct netif *netif))

  Adds your network interface to the netif_list. Allocate a struct
  netif and pass a pointer to this structure as the first argument.
  Give pointers to cleared ip_addr structures when using DHCP,
  or fill them with sane numbers otherwise. The state pointer may be NULL.

  The init function pointer must point to a initialization function for
  your ethernet netif interface. The following code illustrates it's use.*/
  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input);

  /*  Registers the default network interface.*/
  netif_set_default(&gnetif);

  if (EthStatus == (ETH_INIT_FLAG | ETH_LINK_FLAG))
  { 
    /* Set Ethernet link flag */
    gnetif.flags |= NETIF_FLAG_LINK_UP;

    /* When the netif is fully configured this function must be called.*/
    netif_set_up(&gnetif);

  }
  else
  {
    /*  When the netif link is down this function must be called.*/
    netif_set_down(&gnetif);


  /* Set the link callback function, this function is called on change of link status*/
  netif_set_link_callback(&gnetif, ETH_link_callback);
}

主要的有几点:设置IP地址;添加网卡;设置网卡工作起来;

lwip驱动

最关键的是ethernetif.c

位置在:

STSW_STM32070_LwIP_TCP_IP_STM32F4x7堆栈示例\STM32F4x7_ETH_LwIP_V1.1.1\Utilities\Third_Party\lwip-1.4.1\port\STM32F4x7\Standalone\ethernetif.c

针对网卡netif的接口函数:

网卡初始化ethernetif_init

关键点:

设置 linkoutput = low_level_output;

调用 low_level_init();

err_t ethernetif_init(struct netif *netif)
{
  LWIP_ASSERT("netif != NULL", (netif != NULL));
  
#if LWIP_NETIF_HOSTNAME
  /* Initialize interface hostname */
  netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */

  netif->name[0] = IFNAME0;
  netif->name[1] = IFNAME1;
  /* We directly use etharp_output() here to save a function call.
   * You can instead declare your own function an call etharp_output()
   * from it if you have to do some checks before sending (e.g. if link
   * is available...) */
  netif->output = etharp_output;
  netif->linkoutput = low_level_output;

  /* initialize the hardware */
  low_level_init(netif);

  return ERR_OK;
}

底层初始化low_level_init

主要是调用外设库函数,配置DMA描述符,然后启动ETH。

/**
 * In this function, the hardware should be initialized.
 * Called from ethernetif_init().
 *
 * @param netif the already initialized lwip network interface structure
 *        for this ethernetif
 */
static void low_level_init(struct netif *netif)
{
#ifdef CHECKSUM_BY_HARDWARE
  int i; 
#endif
  /* set MAC hardware address length */
  netif->hwaddr_len = ETHARP_HWADDR_LEN;

  /* set MAC hardware address */
  netif->hwaddr[0] =  MAC_ADDR0;
  netif->hwaddr[1] =  MAC_ADDR1;
  netif->hwaddr[2] =  MAC_ADDR2;
  netif->hwaddr[3] =  MAC_ADDR3;
  netif->hwaddr[4] =  MAC_ADDR4;
  netif->hwaddr[5] =  MAC_ADDR5;
  
  /* initialize MAC address in ethernet MAC */ 
  ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr); 

  /* maximum transfer unit */
  netif->mtu = 1500;

  /* device capabilities */
  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;

  /* Initialize Tx Descriptors list: Chain Mode */
  ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
  /* Initialize Rx Descriptors list: Chain Mode  */
  ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);

#ifdef CHECKSUM_BY_HARDWARE
  /* Enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
  for(i=0; i<ETH_TXBUFNB; i++)
    {
      ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
    }
#endif

   /* Note: TCP, UDP, ICMP checksum checking for received frame are enabled in DMA config */

  /* Enable MAC and DMA transmission and reception */
  ETH_Start();

}

网卡输入ethernetif_input

调用low_level_input(),获取输入数据,再调用netif->input()由协议栈处理。

/**
 * This function should be called when a packet is ready to be read
 * from the interface. It uses the function low_level_input() that
 * should handle the actual reception of bytes from the network
 * interface. Then the type of the received packet is determined and
 * the appropriate input function is called.
 *
 * @param netif the lwip network interface structure for this ethernetif
 */
err_t ethernetif_input(struct netif *netif)
{
  err_t err;
  struct pbuf *p;

  /* move received packet into a new pbuf */
  p = low_level_input(netif);

  /* no packet could be read, silently ignore this */
  if (p == NULL) return ERR_MEM;

  /* entry point to the LwIP stack */
  err = netif->input(p, netif);
  
  if (err != ERR_OK)
  {
    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
    pbuf_free(p);
  }
  return err;
}

底层输入low_level_input

从外设库函数获取数据大小及内容,拷贝到lwip分配的pbuf中。

/**
 * Should allocate a pbuf and transfer the bytes of the incoming
 * packet from the interface into the pbuf.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return a pbuf filled with the received packet (including MAC header)
 *         NULL on memory error
   */
static struct pbuf * low_level_input(struct netif *netif)
{
  struct pbuf *p, *q;
  uint32_t len;
  FrameTypeDef frame;
  u8 *buffer;
  __IO ETH_DMADESCTypeDef *DMARxDesc;
  uint32_t bufferoffset = 0;
  uint32_t payloadoffset = 0;
  uint32_t byteslefttocopy = 0;
  uint32_t i=0;  
  
  /* get received frame */
  frame = ETH_Get_Received_Frame();
  
  /* Obtain the size of the packet and put it into the "len" variable. */
  len = frame.length;
  buffer = (u8 *)frame.buffer;
  
  /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  
  if (p != NULL)
  {
    DMARxDesc = frame.descriptor;
    bufferoffset = 0;
    for(q = p; q != NULL; q = q->next)
    {
      byteslefttocopy = q->len;
      payloadoffset = 0;
      
      /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
      while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )
      {
        /* Copy data to pbuf*/
        memcpy( (u8_t*)((u8_t*)q->payload + payloadoffset), (u8_t*)((u8_t*)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
        
        /* Point to next descriptor */
        DMARxDesc = (ETH_DMADESCTypeDef *)(DMARxDesc->Buffer2NextDescAddr);
        buffer = (unsigned char *)(DMARxDesc->Buffer1Addr);
        
        byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
        payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
        bufferoffset = 0;
      }
      /* Copy remaining data in pbuf */
      memcpy( (u8_t*)((u8_t*)q->payload + payloadoffset), (u8_t*)((u8_t*)buffer + bufferoffset), byteslefttocopy);
      bufferoffset = bufferoffset + byteslefttocopy;
    }
  }
  
  /* Release descriptors to DMA */
  DMARxDesc =frame.descriptor;

  /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
  for (i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
  {  
    DMARxDesc->Status = ETH_DMARxDesc_OWN;
    DMARxDesc = (ETH_DMADESCTypeDef *)(DMARxDesc->Buffer2NextDescAddr);
  }
  
  /* Clear Segment_Count */
  DMA_RX_FRAME_infos->Seg_Count =0;
  
  /* When Rx Buffer unavailable flag is set: clear it and resume reception */
  if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)  
  {
    /* Clear RBUS ETHERNET DMA flag */
    ETH->DMASR = ETH_DMASR_RBUS;
    /* Resume DMA reception */
    ETH->DMARPDR = 0;
  }
  return p;
}

底层输出low_level_output

将pbuf的内容交给外设库发送出去。

/**
 * This function should do the actual transmission of the packet. The packet is
 * contained in the pbuf that is passed to the function. This pbuf
 * might be chained.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
 * @return ERR_OK if the packet could be sent
 *         an err_t value if the packet couldn't be sent
 *
 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
 *       strange results. You might consider waiting for space in the DMA queue
 *       to become availale since the stack doesn't retry to send a packet
 *       dropped because of memory failure (except for the TCP timers).
 */

static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
  err_t errval;
  struct pbuf *q;
  u8 *buffer =  (u8 *)(DMATxDescToSet->Buffer1Addr);
  __IO ETH_DMADESCTypeDef *DmaTxDesc;
  uint16_t framelength = 0;
  uint32_t bufferoffset = 0;
  uint32_t byteslefttocopy = 0;
  uint32_t payloadoffset = 0;

  DmaTxDesc = DMATxDescToSet;
  bufferoffset = 0;

  /* copy frame from pbufs to driver buffers */
  for(q = p; q != NULL; q = q->next)
    {
      /* Is this buffer available? If not, goto error */
      if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (u32)RESET)
      {
        errval = ERR_BUF;
        goto error;
      }

      /* Get bytes in current lwIP buffer */
      byteslefttocopy = q->len;
      payloadoffset = 0;

      /* Check if the length of data to copy is bigger than Tx buffer size*/
      while( (byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE )
      {
        /* Copy data to Tx buffer*/
        memcpy( (u8_t*)((u8_t*)buffer + bufferoffset), (u8_t*)((u8_t*)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset) );

        /* Point to next descriptor */
        DmaTxDesc = (ETH_DMADESCTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);

        /* Check if the buffer is available */
        if((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (u32)RESET)
        {
          errval = ERR_USE;
          goto error;
        }

        buffer = (u8 *)(DmaTxDesc->Buffer1Addr);

        byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
        payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
        framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
        bufferoffset = 0;
      }

      /* Copy the remaining bytes */
      memcpy( (u8_t*)((u8_t*)buffer + bufferoffset), (u8_t*)((u8_t*)q->payload + payloadoffset), byteslefttocopy );
      bufferoffset = bufferoffset + byteslefttocopy;
      framelength = framelength + byteslefttocopy;
    }
  
  /* Note: padding and CRC for transmitted frame 
     are automatically inserted by DMA */

  /* Prepare transmit descriptors to give to DMA*/ 
  ETH_Prepare_Transmit_Descriptors(framelength);

  errval = ERR_OK;

error:
  
  /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */
  if ((ETH->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET)
  {
    /* Clear TUS ETHERNET DMA flag */
    ETH->DMASR = ETH_DMASR_TUS;

    /* Resume DMA transmission*/
    ETH->DMATPDR = 0;
  }
  return errval;
}

主循环任务

数据包处理

收到数据包后,直接交给ethernetif_input()处理。

/**
* @brief  Called when a frame is received
* @param  None
* @retval None
*/
void LwIP_Pkt_Handle(void)
{
  /* Read a received packet from the Ethernet buffers and send it to the lwIP for handling */
  ethernetif_input(&gnetif);
}

周期任务

主要是处理时间相关的内容。

/**
* @brief  LwIP periodic tasks
* @param  localtime the current LocalTime value
* @retval None
*/
void LwIP_Periodic_Handle(__IO uint32_t localtime)
{
#if LWIP_TCP
  /* TCP periodic process every 250 ms */
  if (localtime - TCPTimer >= TCP_TMR_INTERVAL)
  {
    TCPTimer =  localtime;
    tcp_tmr();
  }
#endif
  
  /* ARP periodic process every 5s */
  if ((localtime - ARPTimer) >= ARP_TMR_INTERVAL)
  {
    ARPTimer =  localtime;
    etharp_tmr();
  }
  

}

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

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

相关文章

java常用IO流功能——字符流和缓冲流概述

前言&#xff1a; 整理下学习笔记&#xff0c;打好基础&#xff0c;daydayup! 之前说了下了IO流的概念&#xff0c;并整理了字节流&#xff0c;有需要的可以看这篇 java常用应用程序编程接口&#xff08;API&#xff09;——IO流概述及字节流的使用 字符流 FileReader(文件字…

基于注意力机制和损坏特征掩蔽的遮挡人脸识别

Occluded Face Recognition Based on Attention Mechanism and Damaged Feature Masking 摘要 本文提出了一种基于注意力机制&#xff08;BAM&#xff09;和掩模生成器的新型遮挡人脸识别方法。在主干网络中嵌入BAM以提取更多可区分的特征&#xff0c;同时设计掩模生成器来清理…

媒介盒子揭秘0基础写好软文的秘诀

在流量见顶的传播环境下&#xff0c;品牌获取用户注意力的主要方式就在软文&#xff0c;然而有许多品牌在写软文时往往摸不着头脑&#xff0c;不知道怎么写&#xff0c;如何写才能使品牌有效曝光&#xff0c;今天媒介盒子就来和大家聊聊&#xff1a;0基础也能写好软文的秘诀&am…

SAP BAS中Fiori开发的高阶功能(storyboard, navigation, guided development, variant)

1. 前言 在之前的几篇文章中&#xff0c;我介绍了SAP BAS的一些基本功能&#xff0c;包括账户申请&#xff0c;创建工作区&#xff0c;git的使用以及如何step-by-step去创建出你的第一个Fiori项目等等。在本篇中&#xff0c;我将进一步介绍一些在开发Fiori应用程序时会用到的高…

【数仓】DataX软件安装及配置,从mysql同步到hdfs

相关文章 【数仓】基本概念、知识普及、核心技术【数仓】数据分层概念以及相关逻辑【数仓】Hadoop软件安装及使用&#xff08;集群配置&#xff09;【数仓】Hadoop集群配置常用参数说明【数仓】zookeeper软件安装及集群配置【数仓】kafka软件安装及集群配置【数仓】flume软件安…

C语言例4-7:格式字符f的使用例子

%f&#xff0c;实型&#xff0c;小数部分为6位 代码如下&#xff1a; //格式字符f的使用例子 #include<stdio.h> int main(void) {float f 123.456;double d1, d2;d11111111111111.111111111;d22222222222222.222222222;printf("%f,%12f,%12.2f,%-12.2f,%.2f\n&qu…

关于在forEach循环中使用异步,造成forEach里面的函数还未执行完毕,外层的同步已经被执行的问题

使用 原生的 for循环替代forEach循环即可解决问题 1.实例代码&#xff1a; select_Father_comment_sql_res.forEach( (item) > {const Select_FId_children_sql util.format("Select *, \IFNULL(User.UserName,) as CommentUserName, \IFNULL(User.UserName,) as AtU…

2015年认证杯SPSSPRO杯数学建模B题(第一阶段)替换式密码全过程文档及程序

2015年认证杯SPSSPRO杯数学建模 B题 替换式密码 原题再现&#xff1a; 历史上有许多密码的编制方法。较为简单的是替换式密码&#xff0c;也就是将文中出现的字符一对一地替换成其它的符号。对拼音文字而言&#xff0c;最简单的形式是单字母替换加密&#xff0c;也就是以每个…

如何学习VBA_3.2.19:利用Shell函数运行可执行程序

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…

Git 分布式版本控制系统基本概念和操作命令

目录 Git 基本概念 功能特点 工作流程 操作命令 新建代码库 配置 增删文件 代码提交 分支 标签 查看信息 远程同步 撤销 其他 小结 Git Git 是一个开源的分布式版本控制系统&#xff0c;用于跟踪文件的变更历史。它最初由 Linux Torvalds 设计&#xff0c;用于…

JDK,Nginx,Redis安装

创建develop目录 mkdir /usr/local/develop/ cd /usr/local/develop 下载 wget http://nginx.org/download/nginx-1.17.4.tar.gz yum install git git clone https://github.com/arut/nginx-rtmp-module.git 解压文件 tar zxmf nginx-1.17.4.tar.gz 进入解压目录 cd ng…

STL和泛型编程

STL和泛型编程 一.STL六大部件"前开后闭"区间 二.容器(1)顺序容器1.array源码剖析 2.vector源码剖析vector的迭代器 3.list源码剖析迭代器的设计规则关于重载操作符关于重载->和*操作符 4.forward_list源码剖析 5.deque源码剖析底层数据结构操作实现deque的设计de…

力扣面试150 Pow(x, n) 快速幂 负指数

Problem: 50. Pow(x, n) 解题方法 &#x1f468;‍&#x1f3eb; 参考题解 复杂度 时间复杂度: O ( l o g 2 n ) O(log_{2}n) O(log2​n) 空间复杂度: O ( 1 ) O(1) O(1) Code class Solution {public double myPow(double x, int n){if (x 0.0f)return 0.0d;long b…

centos7 装 docker-ce

安装必要的系统工具&#xff1a; sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 命令会以超级用户的身份安装三个软件包&#xff1a;yum-utils&#xff0c;device-mapper-persistent-…

2024.3.2-玄子Share-Mybatis 八股文面试题(共计:48 道 9000 字)

2024.3.2-玄子Share-Mybatis 八股文面试题&#xff08;共计&#xff1a;48 道 9000 字&#xff09; 前言&#xff1a; 本文部分面试题来源于网络仅供学习使用&#xff0c;请支持原作部分面试题有修改润色&#xff0c;部分面试题由我&#xff08;玄子&#xff09;自写面试题根据…

牛客NC12 重建二叉树【中等 dfs Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6 思路 先序遍历第一个值就是根节点&#xff0c;根据这个值可以在中序中划分左右子树&#xff0c; 我们这里已经将一个数划分成两颗子树&#xff0c;那么在递归的使用刚刚的分析…

大模型时代的向量数据库:原理解析和应用案例

大家好&#xff0c;在人工智能领域&#xff0c;数据处理和加工的需求愈发增加。随着人们深入探索AI高级的应用&#xff0c;如图像识别、语音搜索和推荐引擎等&#xff0c;数据的复杂性也在不断地增加。此时传统的数据库存储方式已不能完全满足需求&#xff0c;向量数据库应运而…

大模型知识点汇总——分布式训练

PS&#xff1a;本篇只在宏观上介绍相关概念和技术&#xff0c;不做数学推导和过于细节介绍&#xff0c;旨在快速有一个宏观认知&#xff0c;不拘泥在细节上&#xff0c;导致很混乱。 涉及技术名词 分布式框架等涉及的技术名词很多&#xff0c;很容易让人眼花缭乱&#xff0c;…

vdat文件分段了怎么合并成MP4?批量导入一键合并!

一些监控摄像头、视频录像软件或其他专用设备可能会生成vdat文件作为其录制的视频数据文件。一些浏览器比如夸克下载的视频也会出现vdat格式&#xff0c;因为流媒体播放采用的是分段加载&#xff0c;在网络不好的时候&#xff0c;重新加载对文件整体性损坏比较小&#xff0c;所…

springboot 中Aop注解切面实现收集日志与统计耗时2

一 Aop注解实现切面 1.1 工程结构 Before&#xff1a;前置通知, 在方法执行之前执行 Aroud&#xff1a;环绕通知, 围绕着方法执行 After&#xff1a;后置通知, 在方法执行之后执行 AfterReturning&#xff1a;返回通知, 在方法返回结果之后执行 AfterThrowing&#xff1a;异…