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文章
10895瀏覽量
355728 -
TCP
+關注
關注
8文章
1353瀏覽量
79055 -
DM9000
+關注
關注
0文章
24瀏覽量
16887 -
LwIP
+關注
關注
2文章
86瀏覽量
27149
發布評論請先 登錄
相關推薦
為什么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次下載
評論