LWIP裸机环境下实现TCP与UDP通讯
前面移植了LWIP,并且简单的实用了DHCP的功能,今天来使用一下实际的数据通讯的功能
首先是实现TCP客户端,我先上代码
#ifndef __TCP_CLIENT_H_
#define __TCP_CLIENT_H_
#include "network.h" //连接状态
enum tcp_client_states
{
ES_NONE = ,
ES_RECEIVED, //接收到了数据
ES_CLOSING //连接关闭
}; //TCP服务器状态
struct tcp_client_state
{
u8_t state;
}; #define LWIP_CLIENT_BUF 200 //TCP链接缓存 extern u8 lwip_client_buf[LWIP_CLIENT_BUF]; //定义用来发送和接收数据的缓存 extern u8 lwip_tcp_client_flag; //用于定义lwip tcp client状态 //客户端成功连接到远程主机时调用
err_t Tcp_Client_Connect(void *arg,struct tcp_pcb *tpcb,err_t err); //连接轮询时将要调用的函数
err_t Tcp_Client_Poll(void *arg, struct tcp_pcb *tpcb); //用于连接远程主机
void Tcp_Client_Connect_Remotehost(void); //客户端接收到数据之后将要调用的函数
err_t Tcp_Client_Recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); //关闭连接
void Tcp_Client_Close(struct tcp_pcb *tpcb, struct tcp_client_state* ts); //初始化TCP客户端
void Tcp_Client_Init(void); #endif
#include "tcp_client.h" u8 lwip_tcp_client_flag; //用于定义lwip tcp client状态 //定义一个TCP的协议控制块
struct tcp_pcb* tcp_client_pcb;
//链接的自动回应信息
static const char* respond = "tcp_client connect success\r\n"; u8 lwip_client_buf[LWIP_CLIENT_BUF]; //定义用来发送和接收数据的缓存 //客户端成功连接到远程主机时调用
err_t Tcp_Client_Connect(void *arg,struct tcp_pcb *tpcb,err_t err)
{
struct tcp_client_state* ts;
ts = arg;
ts->state = ES_RECEIVED; //可以开始接收数据了
lwip_tcp_client_flag |= LWIP_CONNECTED; //标记连接成功了
tcp_write(tpcb,respond,strlen(respond),); //回应信息
return ERR_OK;
} //连接轮询时将要调用的函数
err_t Tcp_Client_Poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_client_state* ts;
ts = arg;
// lwip_log("tcp_client_polling!\r\n");
if(ts!=NULL)//连接处于空闲可以发送数据
{
if((lwip_tcp_client_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
tcp_write(tpcb,lwip_client_buf,strlen((char *)lwip_client_buf),);//发送数据
lwip_tcp_client_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
}
}
else
{
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
} //用于连接远程主机
void Tcp_Client_Connect_Remotehost(void)
{
//记住如果此处需要频繁重连的时候记得先关闭已经申请的tcb
//最好将tcb换成全局变量
// Tcp_Client_Close();
Tcp_Client_Init();
} //客户端接收到数据之后将要调用的函数
err_t Tcp_Client_Recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
struct tcp_client_state* ts;
ts = arg; //TCP PCB状态
if(p==NULL)
{
ts->state = ES_CLOSING; //连接关闭了
Tcp_Client_Close(tpcb,ts);
lwip_tcp_client_flag &=~ LWIP_CONNECTED; //清除连接标志
}
else if(err!=ERR_OK)
{ //位置错误释放pbuf
if(p!=NULL)
{
pbuf_free(p);
}
ret_err = err; //得到错误
}
else if(ts->state==ES_RECEIVED)
{//连接收到了新的数据 // printf("服务器新接收的数据:%s\r\n",p->payload);
if((p->tot_len)>=LWIP_CLIENT_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_client_buf,p->payload,);
}
else
{
memcpy(lwip_client_buf,p->payload,p->tot_len);
lwip_client_buf[p->tot_len] = ;
}
lwip_tcp_client_flag |= LWIP_NEW_DATA; //收到了新的数据
tcp_recved(tpcb, p->tot_len); //用于获取接收数据的长度, 表示可以获取更多的数据
pbuf_free(p); //释放内存
ret_err = ERR_OK;
}
else if(ts->state==ES_CLOSING)//服务器关闭了
{
tcp_recved(tpcb, p->tot_len); //远程端口关闭两次,垃圾数据
pbuf_free(p);
ret_err = ERR_OK;
}
else
{ //其他未知状态
tcp_recved(tpcb, p->tot_len);
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err; } //关闭连接
void Tcp_Client_Close(struct tcp_pcb *tpcb, struct tcp_client_state* ts)
{ tcp_arg(tcp_client_pcb, NULL);
tcp_recv(tcp_client_pcb, NULL);
tcp_poll(tcp_client_pcb, NULL, );
if(ts!=NULL)
{
mem_free(ts);
}
tcp_close(tpcb);
} //指定连接的客户端为1300端口
#define TCP_CLIENT_PORT 1300 //初始化TCP客户端
void Tcp_Client_Init(void)
{
struct tcp_client_state* ts;
ip_addr_t ipaddr;
IP4_ADDR(&ipaddr, , , , ); tcp_client_pcb = tcp_new(); //新建一个PCB
if(tcp_client_pcb!=NULL)
{
ts = mem_malloc(sizeof(struct tcp_client_state)); //申请内存
tcp_arg(tcp_client_pcb, ts); //将程序的协议控制块的状态传递给多有的回调函数
//设定TCP的回调函数
tcp_connect(tcp_client_pcb,&ipaddr,TCP_CLIENT_PORT,Tcp_Client_Connect);
tcp_recv(tcp_client_pcb, Tcp_Client_Recv); //指定连接接收到新的数据之后将要调用的回调函数
tcp_poll(tcp_client_pcb, Tcp_Client_Poll, ); //指定轮询时将要调用的回调函数
}
}
我们可以看到,在tcp客户端初始化的时候我们使用了回调函数技术将接收数据和轮询数据的函数添加到了网络的底层轮转中,还要指定链接的端口和ip,但是不需要指定本地端口
同时,我们还在在程序主循环中不停地处理网络事件(因为没有操作系统)
//LWIP查询
void LWIP_Polling(void)
{
if(timer_expired(&input_time,)) //接收包,周期处理函数
{
ethernetif_input(&enc28j60_netif);
}
if(timer_expired(&last_tcp_time,TCP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//TCP处理定时器处理函数
{
tcp_tmr();
}
if(timer_expired(&last_arp_time,ARP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//ARP处理定时器
{
etharp_tmr();
}
if(timer_expired(&last_ipreass_time,IP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//IP重新组装定时器
{
ip_reass_tmr();
}
}
这样,完整的TCP通讯链路就能建成了,数据的使用这样
if((lwip_tcp_client_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP CLIENT Connect ",LCD_BLACK);
if(keyValue == KEY_RIGHT)
{
t_client_cnt++;
sprintf((char*)lwip_client_buf,"tcp_client send %d\r\n",t_client_cnt);
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_client_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
else
{
// Tcp_Client_Connect_Remotehost();//没有连接上,此时处于TCP客户端模式,则尝试重新连接
} if((lwip_tcp_client_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);
lwip_tcp_client_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
}
同理,TCP服务器的流程也差不多,但是多了一个东西,tcp服务器要监听本地某一个特定端口,使用如下
#include "tcp_service.h" struct tcp_pcb* tcp_server_pcb;//定义一个TCP的协议控制块 static const char* respond = "tcp_service connect ok!\r\n"; u8 lwip_tcp_service_flag; //用于定义lwip tcp client状态 u8 lwip_service_buf[LWIP_SERCER_BUF]; //定义用来发送和接收数据的缓存 //初始化LWIP服务器
void Init_TCP_Server(void)
{
err_t err; //LWIP错误信息
tcp_server_pcb = tcp_new(); //新建一个TCP协议控制块
if(tcp_server_pcb!=NULL)
{
err = tcp_bind(tcp_server_pcb,IP_ADDR_ANY,TCP_SERVER_PORT);//绑定本地所有IP地址和端口号 作为服务器不需要知道客户端的IP
if(err==ERR_OK)//成功绑定
{
tcp_server_pcb = tcp_listen(tcp_server_pcb); //开始监听端口
tcp_accept(tcp_server_pcb,Tcp_Server_Accept); //指定监听状态的连接联通之后将要调用的回调函数
}
} } //服务器连接成功后将要调用的函数
err_t Tcp_Server_Accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
err_t ret_err;
struct tcp_server_state* ts; ts = mem_malloc(sizeof(struct tcp_server_state)); //申请内存
if(ts!=NULL)
{
ts->state = ES_SERVER_RECEIVED; //可以接收数据了
lwip_tcp_service_flag |= LWIP_CONNECTED; //已经连接上了
tcp_write(newpcb,respond,strlen(respond),); //回应信息 tcp_arg(newpcb, ts); //将程序的协议控制块的状态传递给多有的回调函数 tcp_recv(newpcb, Tcp_Server_Recv); //指定连接接收到新的数据之后将要调用的回调函数
tcp_err(newpcb, Tcp_Server_Error); //指定连接出错将要调用的函数
tcp_poll(newpcb, Tcp_Server_Poll, ); //指定轮询时将要调用的回调函数
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err; } //连接轮询时将要调用的函数
err_t Tcp_Server_Poll(void *arg, struct tcp_pcb *tpcb)
{
err_t ret_err;
struct tcp_server_state* ts;
ts = arg;
if(ts!=NULL)
{ //连接处于空闲可以发送数据
if((lwip_tcp_service_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
tcp_write(tpcb,lwip_service_buf,strlen((char *)lwip_service_buf),);//发送数据
lwip_tcp_service_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
}
}
else
{
tcp_abort(tpcb);
ret_err = ERR_ABRT;
}
return ret_err;
} //服务器接收到数据之后将要调用的函数
err_t Tcp_Server_Recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
err_t ret_err;
struct tcp_server_state* ts; ts = arg; //TCP PCB状态
if(p==NULL)
{
ts->state = ES_SERVER_CLOSING; //连接关闭了
Tcp_Server_Close(tpcb,ts);
lwip_tcp_service_flag &=~ LWIP_CONNECTED; //清除连接标志
}
else if(err!=ERR_OK)
{ //未知错误,释放pbuf
if(p!=NULL)
{
pbuf_free(p);
}
ret_err = err; //得到错误
}
else if(ts->state==ES_SERVER_RECEIVED)
{//连接收到了新的数据
if((p->tot_len)>=LWIP_SERCER_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_service_buf,p->payload,);
}
else
{
memcpy(lwip_service_buf,p->payload,p->tot_len);
lwip_service_buf[p->tot_len] = ;
} lwip_tcp_service_flag |= LWIP_NEW_DATA; //收到了新的数据 tcp_recved(tpcb, p->tot_len); //用于获取接收数据的长度, 通知LWIP已经读取了数据,可以获取更多的数据
pbuf_free(p); //释放内存
ret_err = ERR_OK;
}
else if(ts->state==ES_SERVER_CLOSING)
{ //服务器关闭了
tcp_recved(tpcb, p->tot_len); //远程端口关闭两次,垃圾数据
pbuf_free(p);
ret_err = ERR_OK;
}
else
{ //其他未知状态
tcp_recved(tpcb, p->tot_len);
pbuf_free(p);
ret_err = ERR_OK;
}
return ret_err; } //连接出错将要调用的函数
void Tcp_Server_Error(void *arg,err_t err)
{
struct tcp_server_state* ts;
ts = arg;
if(ts!=NULL)
{
mem_free(ts);
}
} //关闭连接
void Tcp_Server_Close(struct tcp_pcb *tpcb, struct tcp_server_state* ts)
{
if(ts!=NULL)
{
mem_free(ts);
}
tcp_close(tpcb);
}
可以看到上面的代码多了一个bind的过程
剩下的就是udp通讯了,在之前tcp的源码里面能看到,发送数据的时候不需要专门去做发送函数,指定一个标志位就行了,在轮转的时候程序会自动把数据发送出去,当使用UDP的时候就不行了,因为TCP是面向链接的,而UDP本身就是无连接的,UDP的是使用源码如下
#include "udp_send.h" //该文件即可以接受也可以发送数据
//都是用1500端口进行操作 u8 lwip_udp_send_buf[LWIP_UDP_SEND_BUF]; //定义用来发送和接收数据的缓存
u8 lwip_udp_send_flag; //用于定义lwip tcp client状态 struct udp_pcb* udp_client_pcb;//定义一个UDP的协议控制块
struct pbuf * ubuf_client; //接收到数据包将要调用的函数
void udp_client_rev(void* arg,struct udp_pcb* upcb,struct pbuf* p,struct ip_addr*addr ,u16_t port)
{
if(p!=NULL)
{
if((p->tot_len)>=LWIP_UDP_SEND_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_udp_send_buf,p->payload,);
}
else
{
memcpy(lwip_udp_send_buf,p->payload,p->tot_len);
lwip_udp_send_buf[p->tot_len] = ;
}
lwip_udp_send_flag |= LWIP_NEW_DATA; //收到了新的数据
pbuf_free(p);
}
} //发送数据
void udp_client_send_data(void)
{
err_t err;
if((lwip_udp_send_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
ubuf_client = pbuf_alloc(PBUF_TRANSPORT, strlen((char *)lwip_udp_send_buf), PBUF_RAM); //为发送包分配内存
ubuf_client->payload = lwip_udp_send_buf;
err=udp_send(udp_client_pcb,ubuf_client);//发送数据
if(err!=ERR_OK)
{
//lwip_log("UDP SERVER发送数据失败!");
}
lwip_udp_send_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
pbuf_free(ubuf_client);
}
} //初始化UDP客户端
void Init_UDP_Client(void)
{
//struct ip_addr* ipaddr;
ip_addr_t ipaddr;
IP4_ADDR(&ipaddr, , , , ); //设置本地ip地址
udp_client_pcb = udp_new(); //新建一个UDP协议控制块
if(udp_client_pcb!=NULL)
{
udp_bind(udp_client_pcb,IP_ADDR_ANY,UDP_CLIENT_PORT); //
udp_connect(udp_client_pcb,&ipaddr,UDP_CLIENT_PORT); //设置连接到远程主机
udp_recv(udp_client_pcb,udp_client_rev,NULL); //指定收到数据包时的回调函数
}
}
这是一个UDP的客户端,在初始化的时候指明了目的主机的地址和端口号,连接到目的主机上
接下来是一个UDP的服务器
#include "udp_recv.h" struct udp_pcb* udp_server_pcb;//定义一个UDP的协议控制块
struct pbuf * ubuf; u8 lwip_udp_recv_buf[LWIP_UDP_RECV_BUF]; //定义用来发送和接收数据的缓存
u8 lwip_udp_recv_flag; //用于定义lwip tcp client状态 //接收到数据包将要调用的函数
void Udp_Server_Recv(void* arg,struct udp_pcb* upcb,struct pbuf* p,struct ip_addr*addr ,u16_t port)
{
if(p!=NULL)
{
if((p->tot_len)>=LWIP_UDP_RECV_BUF)
{ //如果收的的数据大于缓存
((char*)p->payload)[] = ;
memcpy(lwip_udp_recv_buf,p->payload,);
}
else
{
memcpy(lwip_udp_recv_buf,p->payload,p->tot_len);
lwip_udp_recv_buf[p->tot_len] = ;
}
lwip_udp_recv_flag |= LWIP_NEW_DATA; //收到了新的数据
udp_server_pcb->remote_ip = *addr; //记录远程主机的IP和端口号
udp_server_pcb->remote_port = port;
pbuf_free(p);
}
} //发送数据
void Udp_Server_Send_Data(void)
{
err_t err;
if((lwip_udp_recv_flag&LWIP_SEND_DATA)==LWIP_SEND_DATA)
{
ubuf = pbuf_alloc(PBUF_TRANSPORT, strlen((char *)lwip_udp_recv_buf), PBUF_RAM);
ubuf->payload = lwip_udp_recv_buf;
err=udp_send(udp_server_pcb,ubuf);//发送数据
if(err!=ERR_OK)
{
//do something
}
lwip_udp_recv_flag &=~LWIP_SEND_DATA; //清除发送数据的标志
pbuf_free(ubuf);
}
} //初始化UDP服务器
void Init_UDP_Server(void)
{
udp_server_pcb = udp_new(); //新建一个UDP协议控制块
if(udp_server_pcb!=NULL)
{
udp_bind(udp_server_pcb,IP_ADDR_ANY,UDP_RECV_PORT); //监听一个UDP端口
udp_recv(udp_server_pcb,Udp_Server_Recv,NULL); //指定收到数据包时的回调函数
}
}
可以看到,UDP的服务器在使用的时候没有主动去连接那个IP,他只是自己绑定了自己的某个端口,算是客户端和服务器编程的两种差异
给一个使用文件
#include "mainInclude.h" #include "lwip/init.h"
#include "lwip/ip.h"
#include "lwip/dhcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/ip_frag.h"
#include "lwip/dns.h"
#include "netif/etharp.h"
#include "netif/ethernetif.h"
#include "arch/sys_arch.h" #define CLOCKTICKS_PER_MS 10 //定义时钟节拍 static ip_addr_t ipaddr, netmask, gw; //定义IP地址
struct netif enc28j60_netif; //定义网络接口
u32_t input_time;
u32_t last_arp_time;
u32_t last_tcp_time;
u32_t last_ipreass_time; u32_t last_dhcp_fine_time;
u32_t last_dhcp_coarse_time;
u32 dhcp_ip=; //LWIP查询
void LWIP_Polling(void)
{
if(timer_expired(&input_time,)) //接收包,周期处理函数
{
ethernetif_input(&enc28j60_netif);
}
if(timer_expired(&last_tcp_time,TCP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//TCP处理定时器处理函数
{
tcp_tmr();
}
if(timer_expired(&last_arp_time,ARP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//ARP处理定时器
{
etharp_tmr();
}
if(timer_expired(&last_ipreass_time,IP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//IP重新组装定时器
{
ip_reass_tmr();
}
} int main(void)
{
u8 t_client_cnt = ;
u8 t_server_cnt = ;
u8 t_send_cnt = ;
u8 t_recv_cnt = ;
NVIC_Group_Init();//系统默认中断分组
Debug_Serial_Init();
Delay_Init();
Led_Init();
Key_Exti_Init();
LCD_Init();
LCD_Clear(LCD_BLACK); IP4_ADDR(&ipaddr, , , , ); //设置本地ip地址
IP4_ADDR(&gw, , , , ); //网关
IP4_ADDR(&netmask, , , , ); //子网掩码 //初始化LWIP定时器
init_lwip_timer();
//初始化LWIP协议栈,执行检查用户所有可配置的值,初始化所有的模块
lwip_init(); //添加网络接口
while((netif_add(&enc28j60_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input)==NULL))
{
LCD_ShowString(,,,,(u8*)"ENC28J60 Init Failed ",LCD_BLACK);
Delay_Ms();
LCD_ShowString(,,,,(u8*)" ",LCD_BLACK);
Delay_Ms();
}
LCD_ShowString(,,,,(u8*)"ENC28J60 Init OK ",LCD_BLACK);
//注册默认的网络接口
netif_set_default(&enc28j60_netif);
//建立网络接口用于处理通信
netif_set_up(&enc28j60_netif); Tcp_Client_Init();//初始化tcp客户端 LCD_ShowString(,,,,(u8*)"TCP CLIENT INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TCP CLIENT Disconnect ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); Init_TCP_Server();
LCD_ShowString(,,,,(u8*)"TCP SERVER INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TCP SERVER Disconnect ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); Init_UDP_Client();
LCD_ShowString(,,,,(u8*)"UDP SEND INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); Init_UDP_Server();//初始化UDP接收端
LCD_ShowString(,,,,(u8*)"UDP RECV INIT ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"RX: ",LCD_BLACK);
LCD_ShowString(,,,,(u8*)"TX: ",LCD_BLACK); while()
{
LWIP_Polling();
if((lwip_tcp_client_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP CLIENT Connect ",LCD_BLACK);
if(keyValue == KEY_RIGHT)
{
t_client_cnt++;
sprintf((char*)lwip_client_buf,"tcp_client send %d\r\n",t_client_cnt);
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_client_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
else
{
// Tcp_Client_Connect_Remotehost();//没有连接上,此时处于TCP客户端模式,则尝试重新连接
} if((lwip_tcp_client_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_client_buf,LCD_BLACK);
lwip_tcp_client_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} if((lwip_tcp_service_flag&LWIP_CONNECTED)==LWIP_CONNECTED)
{
LCD_ShowString(,,,,(u8*)"TCP SERVER Connect ",LCD_BLACK);
if(keyValue == KEY_LEFT)
{
t_server_cnt++;
sprintf((char*)lwip_service_buf,"tcp_service send %d\r\n",t_server_cnt);
LCD_ShowString(,,,,(u8*)lwip_service_buf,LCD_BLACK);//显示当前发送数据
lwip_tcp_service_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
}
}
if((lwip_tcp_service_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_service_buf,LCD_BLACK);
lwip_tcp_service_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} if(keyValue == KEY_UP)
{
t_send_cnt++;
sprintf((char*)lwip_udp_send_buf,"udp_send send %d\r\n",t_send_cnt);
LCD_ShowString(,,,,(u8*)lwip_udp_send_buf,LCD_BLACK);//显示当前发送数据
lwip_udp_send_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
udp_client_send_data();
} if((lwip_udp_send_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_udp_send_buf,LCD_BLACK);
lwip_udp_send_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} if(keyValue == KEY_DOWN)
{
t_recv_cnt++;
sprintf((char*)lwip_udp_recv_buf,"udp_recv send %d\r\n",t_send_cnt);
LCD_ShowString(,,,,(u8*)lwip_udp_recv_buf,LCD_BLACK);//显示当前发送数据
lwip_udp_recv_flag |= LWIP_SEND_DATA; //标记有数据需要发送
keyValue = ;
Udp_Server_Send_Data();
} if((lwip_udp_recv_flag&LWIP_NEW_DATA)==LWIP_NEW_DATA)
{
LCD_ShowString(,,,,(u8*)lwip_udp_recv_buf,LCD_BLACK);
lwip_udp_recv_flag &=~LWIP_NEW_DATA; //清除接受数据的标志
} Delay_Ms();
}
} void USB_LP_CAN1_RX0_IRQHandler(void)
{ } void USBWakeUp_IRQHandler(void)
{
// EXTI->PR|=1<<18;//清除USB唤醒中断挂起位
}
完整的工程路径如下
http://download.csdn.net/detail/dengrengong/8555627
LWIP裸机环境下实现TCP与UDP通讯的更多相关文章
- LWIP裸机环境下实现TCP与UDP通讯(转)
源: LWIP裸机环境下实现TCP与UDP通讯
- qrc资源文件加载后,裸机环境下图片不显示
问题描述:在qt开发环境下,使用qss进行界面美化工作,里面包含许多图片资源.最后项目决定把这些图片资源和代码一起打包.然后就把图片资源和qss文件一起编入qrc文件中进行编译.在本机开发环境下是没有 ...
- onps栈使用说明(3)——tcp、udp通讯测试
4. tcp客户端 在协议栈源码工程下,存在一个用vs2015建立的TcpServerForStackTesting工程.其运行在windows平台下,模拟实际应用场景下的tcp服务器.当tcp客户端 ...
- UNP(一):网络编程角度下的TCP、UDP协议
此博文是学习UNP(UNIX Network Programming)后的读书笔记,供以后自己翻阅回想知识. TCP.UDP概述 在前面<计算机网络与TCP/IP>栏目下已经介绍过一些关于 ...
- [19/04/15-星期一] 基于Socket(套接字)的TCP和UDP通讯的实现
一.TCP 在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序, 简称服务器.一旦通讯建立,则客户端和 ...
- CentOS裸机环境下安装php-7.3.1
安装步骤如下 安装必要的软件 获取源码 编译安装 安装过程可能遇到的一些问题 编译参数详解 安装步骤如下 安装必要的软件 yum install -y autoconf automake libtoo ...
- 在Linux环境下使用TCP的keepalive机制
Linux内置支持keepalive机制,为了使用它,你须要使能TCP/IP网络,为了可以配置内核在执行时的參数.你还须要procfs和sysctl的支持. 这个过程涉及到keepalive使用的三个 ...
- LwIP raw api下使用tcp keep alive
// The following code is implemented after tcp_new() or in tcp_connected call back... xxx_connected( ...
- 痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...
随机推荐
- Android Skia和2D图形系统 .
Android Skia 和 2D 图形系统 1 Skia 概述 Skia 是 Google 一个底层的图形.图像.动画. SVG .文本等多方面的图形库,是 Android 中图形系统的引擎. Sk ...
- Spring Boot 系列教程5-热部署-devtools模块
devtools模块 devtools模块,是为开发者服务的一个模块.主要的功能就是代码修改后一般在5秒之内就会自动重新加载至服务器,相当于restart成功. 原理 简单原理 在发现代码有更改之后, ...
- 解决编译时出现的警告:format string is not a string literal (potentially insecure)
NSLog([NSString stringWithFormat:@"%@/%@B.jpg", createDir, uuid]);//这是我的写法 应该写成 NSString * ...
- ngnix配置文件
使用nginx最大的好处就是负载均衡. #设定负载均衡的服务器列表 upstream service{ server 10.4.29.174:7477; } server { ...
- 为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
在Android硬件抽象层(HAL)概要介绍和学习计划一文中,我们简要介绍了在Android系统为为硬件编写驱动程序的方法.简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的 ...
- 在win7/8/10鼠标右键添加按下SHIFT键时弹出的“在此处打开命令窗口”
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Drive\shell\cmd]@="@shell32.dll,-8506&q ...
- 指针--摘自C++技术网 作者dx
“指针是什么?”“指针就是一种数据类型.”“你确定?”“那数据类型是什么?额,这个???类型就是类型,还能怎么解释嘛.”“指针有多少种?”“指针有好多种,比如整型指针,字符指针等等.”“指针是怎么确定 ...
- js框架——angular.js(6)
1. ng-class 这个指令是用来绑定一个或者多个css代码.它的值一般是一个表达式,也可以是函数什么的,只要返回的确实是一个类的名字就可以—— ng-class="nextPageDi ...
- js html 交互监听事件学习
事件处理程序(handler): HTML事件处理程序: <input type="button" value="Click Here" onclick= ...
- Disassembly3:variable
Initializer C++ Primer上说:如果未初始化的Built-in type是定义在function外部的,那么它将自动被初始化为“0”:如果uninitialized的built-in ...