1.LWIP介紹
lwip是瑞典計(jì)算機(jī)科學(xué)院網(wǎng)絡(luò)嵌入式系統(tǒng)小組(SICS)的Adam Dunkels(亞當(dāng)·鄧克爾) 開發(fā)的一個(gè)小型開源的TCP/IP協(xié)議棧。實(shí)現(xiàn)的重點(diǎn)是在保持 TCP 協(xié)議主要功能的基礎(chǔ)上減少對RAM的占用。
LwIP是Light Weight(輕型)IP 協(xié)議,有無操作系統(tǒng)的支持都可以運(yùn)行。LwIP 實(shí)現(xiàn)的重點(diǎn)是在保持TCP協(xié)議 主要功能的基礎(chǔ)上減少對RAM的占用,它只需十幾KB的RAM和 40K左右的ROM就可以運(yùn)行,這使LwIP協(xié)議棧適合在低端的嵌入式系統(tǒng)中使用。
2.TCP服務(wù)器搭建
硬件平臺:STM32F103ZE開發(fā)板、DM9000有線網(wǎng)卡
開發(fā)環(huán)境:KEIL5
#include "lwip_config.h"
#include "lwip/tcp.h"
/*接收成功回調(diào)函數(shù)*/
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;
}
/*客戶端連接成功回調(diào)函數(shù)*/
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服務(wù)器創(chuàng)建*/
struct tcp_pcb *new_tcp;//tcp網(wǎng)絡(luò)信息(套接字)
u8 LWIP_CreateTcpServer(u16 port)
{
/*1.建立一個(gè)新的網(wǎng)卡設(shè)備*/
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;//綁定端口號失敗
}
/*開始監(jiān)聽*/
new_tcp=tcp_listen(new_tcp);
/*等待客戶端連接*/
tcp_accept(new_tcp,tcp_client);
return 0;
}
3.主函數(shù)
#include "dm9000.h"
#include "lwip_config.h"
u8 buff_tx[]="LWIP協(xié)議使用示例,發(fā)送數(shù)據(jù)測試示例.";
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,"網(wǎng)卡信息");//顯示字符串
stat=DM9000_Get_SpeedAndDuplex();//獲取連接狀態(tài)和工作方式
if(stat!=0xff)
{
printf("網(wǎng)卡速度:%d Mbps 模式:%srn",(stat&0x02)?10:100,(stat&0x01)?"全雙工":"半雙工");
snprintf(buff,sizeof(buff),"網(wǎng)卡速度:%d MHZt %s",(stat&0x02)?10:100,(stat&0x01)?"全雙工":"半雙工");
LCD_ShowStr(30,30+20*3,16,(u8 *)buff);//網(wǎng)卡速度
}
else
{
printf("DM9000網(wǎng)卡狀態(tài)信息獲取失敗!rn");
LCD_ShowStr(30,30+20*3,16,(u8 *)"獲取網(wǎng)卡信息失敗!");//網(wǎng)卡速度
}
LWIP_Config_Init();//LWIP協(xié)議棧初始化
while(!lwip_dhcp_stat)//等待IP分配成功
{
LWIP_DataUpdata();
}
TIMx_Init(TIM6,72,1000);
TIM6->CR1|=1<<0;
LWIP_CreateTcpServer(8899);//創(chuàng)建服務(wù)器
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);
}
}
}
運(yùn)行效果:
4.相關(guān)函數(shù)介紹
4.1.建立TCP連接函數(shù)tcp_new
struct tcp_pcb *tcp_new(void) 函數(shù)功能:建立一個(gè)新的連接標(biāo)志(pcb) 形 參:無 返回值: pcb 正常建立了連接標(biāo)志,返回建立的 pcb NULL 新的 pcb 內(nèi)存不可用時(shí) |
4.2.綁定IP和端口號tcp_bind
err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) 函數(shù)功能:綁定本地 IP 地址和端口號 形 參: pcb 準(zhǔn)備綁定的連接,類似于 BSD 標(biāo)準(zhǔn)中的 Sockets Ipaddr 綁定的 IP 地址。如果為 IP_ADDR_ANY,則將連接綁定到所有的本地 IP 地址上 port 綁定的本地端口號。注意:千萬不要和其它的應(yīng)用程序產(chǎn)生沖突 返回值: ERR_OK 正確地綁定了指定的連接 ERR_USE 指定的端口號已經(jīng)綁定了一個(gè)連接,產(chǎn)生了沖突 |
4.3.使指定連接進(jìn)入監(jiān)聽狀態(tài)tcp_listen
struct tcp_pcb *tcp_listen (struct tcp_pcb *pcb) 函數(shù)功能:使指定的連接開始進(jìn)入監(jiān)聽狀態(tài) 形 參: pcb 指定將要進(jìn)入監(jiān)聽狀態(tài)的連接 返回值: pcb 返回一個(gè)新的連接標(biāo)志 pcb,它作為一個(gè)參數(shù)傳遞給將要被分派的函數(shù)。這樣做的原因是處于監(jiān)聽狀態(tài)的 連接一般只需要較小的內(nèi)存,于是函數(shù) tcp_listen()就會收回原始連接的內(nèi)存,而重新分配一個(gè)較小內(nèi)存塊供處 于監(jiān)聽狀態(tài)的連接使用。 NULL 監(jiān)聽狀態(tài)的連接的內(nèi)存塊不可用時(shí),返回 NULL。如果這樣的話,作為參數(shù)傳遞給函數(shù)tcp_listen()的 pcb 所占用的內(nèi)存將不能夠被分配。 |
4.4.等待客戶端連接tcp_accept
void tcp_accept(struct tcp_pcb pcb,err_t ( accept)(void *arg,struct tcp_pcb *newpcb,err_t err)) 函數(shù)功能:指定處于監(jiān)聽狀態(tài)的連接接通后將要調(diào)用的回調(diào)函數(shù) 形 參: pcb 指定一個(gè)處于監(jiān)聽狀態(tài)的連接 ? accept 指定連接接通后將要調(diào)用的回調(diào)函數(shù) 返回值:無 |
-
STM32
+關(guān)注
關(guān)注
2270文章
10900瀏覽量
355985 -
TCP
+關(guān)注
關(guān)注
8文章
1353瀏覽量
79070 -
DM9000
+關(guān)注
關(guān)注
0文章
24瀏覽量
16895 -
LwIP
+關(guān)注
關(guān)注
2文章
86瀏覽量
27169
發(fā)布評論請先 登錄
相關(guān)推薦
評論