STM32之LWIP网络协议栈TCP服务器创建

STM32之LWIP网络协议栈TCP服务器创建

1.LWIP介绍

  lwip是瑞典计算机科学院网络嵌入式系统小组(SICS)的Adam Dunkels(亚当·邓克尔) 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持 TCP 协议主要功能的基础上减少对RAM的占用。
  LwIP是Light Weight(轻型)IP 协议,有无操作系统的支持都可以运行。LwIP 实现的重点是在保持TCP协议 主要功能的基础上减少对RAM的占用,它只需十几KB的RAM和 40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。

STM32移植LWIP协议栈示例:https://blog.csdn.net/weixin_44453694/article/details/123119624

2.TCP服务器搭建

硬件平台:STM32F103ZE开发板、DM9000有线网卡
开发环境:KEIL5

#include "lwip_config.h"
#include "lwip/tcp.h"
/*接收成功回调函数*/
u8 buff[1024];
u16 rx_len=0;
err_t tcp_recv_func(void *arg, struct tcp_pcb *tpcb,struct pbuf *p, err_t err)
{
	memset(buff,0,sizeof(buff));
	rx_len=0;
	if(p==NULL)
	{
			clinet_stat=0;
			printf("[%d.%d.%d.%d:%d]:客户端断开连接\r\n",(u8)(tpcb->remote_ip.addr),
														(u8)(tpcb->remote_ip.addr>>8),
														(u8)(tpcb->remote_ip.addr>>16),
														(u8)(tpcb->remote_ip.addr>>24),
														tpcb->remote_port);
	}
	else
	{
		if(p->tot_len==p->len)
		{
			memcpy(buff,p->payload,p->len);
			rx_len=p->len;
			pbuf_free(p);
		}
		else
		{
			struct pbuf *temp=p;
			struct pbuf *q=temp;
			while(temp!=NULL)
			{
				memcpy(buff+rx_len,temp->payload,temp->len);
				q=temp;
				temp=temp->next;
				rx_len+=temp->len;
				pbuf_free(q);
			}
		}
		buff[rx_len]='\0';
		printf("[%d.%d.%d.%d:%d]:%s\r\n",(u8)(tpcb->remote_ip.addr),
										(u8)(tpcb->remote_ip.addr>>8),
										(u8)(tpcb->remote_ip.addr>>16),
										(u8)(tpcb->remote_ip.addr>>24),
										tpcb->remote_port,
										buff);
	}
	return ERR_OK;
}
/*客户端连接成功回调函数*/
u8 client_addr[4];//IP地址
u16 client_prot=0;
u8 clinet_stat=0;
err_t tcp_client(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	client_addr[0]=newpcb->remote_ip.addr>>0;
	client_addr[1]=newpcb->remote_ip.addr>>8;
	client_addr[2]=newpcb->remote_ip.addr>>16;
	client_addr[3]=newpcb->remote_ip.addr>>24;	
	clinet_stat=1;
	printf("客户端连接成功:%d.%d.%d.%d:%d\r\n",client_addr[0],client_addr[1],client_addr[2],client_addr[3],newpcb->remote_port);
	new_tcp=newpcb;
	tcp_recv(newpcb,tcp_recv_func);
	return ERR_OK;
}
/*TCP服务器创建*/
struct tcp_pcb *new_tcp;//tcp网络信息(套接字)
u8 LWIP_CreateTcpServer(u16 port)
{
	/*1.建立一个新的网卡设备*/
	new_tcp=tcp_new();
	if(new_tcp==NULL)return 1;
	/*2.绑定IP地址和端口号*/
	if(tcp_bind(new_tcp, IP_ADDR_ANY,port)!=ERR_OK)
	{
		return 2;//绑定端口号失败
	}
	/*开始监听*/
	new_tcp=tcp_listen(new_tcp);
	/*等待客户端连接*/
	tcp_accept(new_tcp,tcp_client);
	return 0;
}

3.主函数

#include "dm9000.h"
#include "lwip_config.h"
u8 buff_tx[]="LWIP协议使用示例,发送数据测试示例.";
int main()
{
	char buff[200];
	u8 stat;
	u8 key;
	Beep_Init();
	Led_Init();
	Key_Init();
	W25Q64_Init();
	Usartx_Init(USART1,115200,72);
	TIMx_Init(TIM2,72,20*1000);
	IIC_Init();
	printf("初始化完成\r\n");
	NT35310_Init();
	/*DM9000初始化*/
	LCD_ShowStr(30,30,16,"DM9000初始化中。。。");//显示字符串
	if(DM9000_Init()==0)
	{
		printf("DM9000初始化成功\r\n");
		LCD_ShowStr(30,30+20,16,"DM9000\t OK!");//显示字符串
	}
	else 
	{
		printf("DM9000初始化失败\r\n");
		LCD_ShowStr(30,30+20,16,"DM9000\t ERR!");//显示字符串
	}
	/*获取DM9000工作模式*/
	LCD_ShowStr(128,30+20*2,16,"网卡信息");//显示字符串
	stat=DM9000_Get_SpeedAndDuplex();//获取连接状态和工作方式
	if(stat!=0xff)
	{
		printf("网卡速度:%d Mbps 模式:%s\r\n",(stat&0x02)?10:100,(stat&0x01)?"全双工":"半双工");
		snprintf(buff,sizeof(buff),"网卡速度:%d MHZ\t %s",(stat&0x02)?10:100,(stat&0x01)?"全双工":"半双工");
		LCD_ShowStr(30,30+20*3,16,(u8 *)buff);//网卡速度
		
	}
	else 
	{
		printf("DM9000网卡状态信息获取失败!\r\n");
		LCD_ShowStr(30,30+20*3,16,(u8 *)"获取网卡信息失败!");//网卡速度
	}
	LWIP_Config_Init();//LWIP协议栈初始化
	while(!lwip_dhcp_stat)//等待IP分配成功
	{
		LWIP_DataUpdata();
	}
	TIMx_Init(TIM6,72,1000);
	TIM6->CR1|=1<<0;
	LWIP_CreateTcpServer(8899);//创建服务器
	while(1)
	{
		LWIP_DataUpdata();
		key=Key_Scan();
		if(key && clinet_stat)
		{
			tcp_write(new_tcp,buff_tx,strlen((char *)buff_tx),1);
			tcp_output(new_tcp);
		}
	}
}

运行效果:
在这里插入图片描述

4.相关函数介绍

  1.建立TCP连接函数tcp_new

struct tcp_pcb *tcp_new(void)
函数功能:建立一个新的连接标志(pcb)
形 参:无
返回值: pcb 正常建立了连接标志,返回建立的 pcb
    NULL 新的 pcb 内存不可用时

  2.绑定IP和端口号tcp_bind

err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
函数功能:绑定本地 IP 地址和端口号
形 参: pcb 准备绑定的连接,类似于 BSD 标准中的 Sockets
    Ipaddr 绑定的 IP 地址。如果为 IP_ADDR_ANY,则将连接绑定到所有的本地 IP 地址上
    port 绑定的本地端口号。注意:千万不要和其它的应用程序产生冲突
返回值: ERR_OK 正确地绑定了指定的连接
    ERR_USE 指定的端口号已经绑定了一个连接,产生了冲突

  3.使指定连接进入监听状态tcp_listen

struct tcp_pcb *tcp_listen (struct tcp_pcb *pcb)
函数功能:使指定的连接开始进入监听状态
形 参: pcb 指定将要进入监听状态的连接
返回值: pcb 返回一个新的连接标志 pcb,它作为一个参数传递给将要被分派的函数。这样做的原因是
      处于监听状态的连接一般只需要较小的内存,于是函数 tcp_listen()就会收回原始连接的内存,
      而重新分配一个较小内存块供处于监听状态的连接使用。
    NULL 监听状态的连接的内存块不可用时,返回 NULL。如果这样的话,作为参数传递给函
       数tcp_listen()的 pcb 所占用的内存将不能够被分配。

  4.等待客户端连接tcp_accept

void tcp_accept(struct tcp_pcb pcb,err_t ( accept)(void *arg,struct tcp_pcb *newpcb,err_t err))
函数功能:指定处于监听状态的连接接通后将要调用的回调函数
形 参: pcb 指定一个处于监听状态的连接
   accept 指定连接接通后将要调用的回调函数
返回值:无

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Stm32LwIP TCP是指在Stm32微控制器上使用LwIP协议栈进行TCP通信。根据引用\[1\]中的描述,你在调试tcp_connect()函数时遇到了一些问题。其中可能的原因有几个。首先,网上的资料大多是将Stm32作为服务器使用,而很少是将其作为客户端使用,这可能导致配置PC服务器变得困难。其次,你可能没有找到相关的资料,只能自己调试。最后,你怀疑自己搭建的服务器有问题,或者电脑的防火墙可能会影响连接。 根据引用\[2\]中的代码片段,你在初始化函数中创建了一个TCP控制块,并将其绑定到本地IP地址和端口号。然后将连接状态设置为LISTEN,并指定在建立连接时调用的函数。 根据引用\[3\]中的描述,tcp_bind()函数用于绑定端口号和IP地址,tcp_listen()函数用于进入监听状态并检查连接,tcp_accept()函数用于处理客户端连接后的回调函数。 综上所述,你遇到的问题可能是由于配置问题、代码错误或网络设置问题导致的。你可以检查你的网络设置、代码逻辑和防火墙设置来解决这些问题。 #### 引用[.reference_title] - *1* [利用stm32lwip TCP/IP协议栈的通信的思路](https://blog.csdn.net/weixin_31313629/article/details/119470770)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [STM32 LWIP TCP以太网传输数据](https://blog.csdn.net/u012246376/article/details/45893235)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_阿水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值