1.LWIP介绍
lwip是瑞典计算机科学院网络嵌入式系统小组(SICS)的Adam Dunkels(亚当·邓克尔) 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持 TCP 协议主要功能的基础上减少对RAM的占用。
LwIP是Light Weight(轻型)IP 协议,有无操作系统的支持都可以运行。LwIP 实现的重点是在保持TCP协议 主要功能的基础上减少对RAM的占用,它只需十几KB的RAM和 40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。
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]:客户端断开连接rn",(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]='�';
printf("[%d.%d.%d.%d:%d]:%srn",(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:%drn",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("初始化完成rn");
NT35310_Init();
/*DM9000初始化*/
LCD_ShowStr(30,30,16,"DM9000初始化中。。。");//显示字符串
if(DM9000_Init()==0)
{
printf("DM9000初始化成功rn");
LCD_ShowStr(30,30+20,16,"DM9000t OK!");//显示字符串
}
else
{
printf("DM9000初始化失败rn");
LCD_ShowStr(30,30+20,16,"DM9000t ERR!");//显示字符串
}
/*获取DM9000工作模式*/
LCD_ShowStr(128,30+20*2,16,"网卡信息");//显示字符串
stat=DM9000_Get_SpeedAndDuplex();//获取连接状态和工作方式
if(stat!=0xff)
{
printf("网卡速度:%d Mbps 模式:%srn",(stat&0x02)?10:100,(stat&0x01)?"全双工":"半双工");
snprintf(buff,sizeof(buff),"网卡速度:%d MHZt %s",(stat&0x02)?10:100,(stat&0x01)?"全双工":"半双工");
LCD_ShowStr(30,30+20*3,16,(u8 *)buff);//网卡速度
}
else
{
printf("DM9000网卡状态信息获取失败!rn");
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.相关函数介绍
4.1.建立TCP连接函数tcp_new
struct tcp_pcb *tcp_new(void) 函数功能:建立一个新的连接标志(pcb) 形 参:无 返回值: pcb 正常建立了连接标志,返回建立的 pcb NULL 新的 pcb 内存不可用时 |
4.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 指定的端口号已经绑定了一个连接,产生了冲突 |
4.3.使指定连接进入监听状态tcp_listen
struct tcp_pcb *tcp_listen (struct tcp_pcb *pcb) 函数功能:使指定的连接开始进入监听状态 形 参: pcb 指定将要进入监听状态的连接 返回值: pcb 返回一个新的连接标志 pcb,它作为一个参数传递给将要被分派的函数。这样做的原因是处于监听状态的 连接一般只需要较小的内存,于是函数 tcp_listen()就会收回原始连接的内存,而重新分配一个较小内存块供处 于监听状态的连接使用。 NULL 监听状态的连接的内存块不可用时,返回 NULL。如果这样的话,作为参数传递给函数tcp_listen()的 pcb 所占用的内存将不能够被分配。 |
4.4.等待客户端连接tcp_accept
void tcp_accept(struct tcp_pcb pcb,err_t ( accept)(void *arg,struct tcp_pcb *newpcb,err_t err)) 函数功能:指定处于监听状态的连接接通后将要调用的回调函数 形 参: pcb 指定一个处于监听状态的连接 accept 指定连接接通后将要调用的回调函数 返回值:无 |
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
STM32
+关注
关注
2270文章
10900浏览量
355915 -
TCP
+关注
关注
8文章
1353浏览量
79068 -
DM9000
+关注
关注
0文章
24浏览量
16892 -
LwIP
+关注
关注
2文章
86浏览量
27166
发布评论请先 登录
相关推荐
为什么LWIP双向发送大量数据时网络协议栈会崩溃?
/?36380,貌似bug已经解决了,不知道有补丁没有。同样是这个移植的协议栈,跑跑原子教材中普通的TCP回响服务器例程是没问题的,很久都不会挂掉,但一开始VNC就不行了。
发表于 11-04 03:19
怎么实现的基于TCP/IP协议栈的简易服务器?
本文以SPCE061A为主控制器,DM9000为以太网MAC控制器,配合一定的外围威廉希尔官方网站
而实现的基于TCP/IP协议栈的简易
发表于 05-31 06:34
LwIP协议栈开发嵌入式网络的三种方法有何关系
服务器端通信为例,分析三种方法以及之间的关系,着重介绍基于raw API的应用程序设计。 LwIP协议栈开发嵌入式网络的三种方法分析 摘要轻
发表于 08-05 07:55
LwIP协议栈开发嵌入式网络有哪几种方法
TCP服务器端通信为例,分析三种方法以及之间的关系,着重介绍基于raw API的应用程序设计。最后在ST公司STM32F107微处理器平台上验证,并给出了测试结果。关键词
发表于 08-06 07:33
TCP服务器创建过程
用过正点原子LWIP服务器例程开发的朋友可能知道,例程的设计是只支持一个客户端连接的,但实际应用中往往需要用到多客户端连接。下面是在正点原子扩展例程网络实验14 NETCONN_TCP
发表于 08-24 08:03
在BL706上基于LwIP协议栈实现一个HTTP服务器
是万维网的数据通信的基础。本 demo 主要是在 BL706 上基于 LwIP 协议栈,实现一个 HTTP 服务器,在 BL706 上部署了一个简单的网页,然后我们可以通过浏览
发表于 07-04 18:13
【技术精选】嵌入式STM32原创征文活动精选文章
应用案例基于PAJ7620和STM32手势识别应用案例STM32应用案例 基于STM32F103ZE开发的数码相册基于STM32的小说阅读器
发表于 07-27 18:26
使用LwIP TCP/IP栈,在STM32Cube上开发应用
电子发烧友网站提供《使用LwIP TCP/IP栈,在STM32Cube上开发应用.pdf》资料免费下载
发表于 09-21 11:03
•6次下载
评论