STM32 LWIP(裸机) RAW接口通讯——TCP API讲解(含源码)
目录
LWIP移植:
TCP裸机编程:
参考(官网API讲解链接):
TCP客户端连接 RAW API:
TCP客户端发起连接源码:
TCP客户端数据发送/接收函数 RAW API:
TCP客户端数据发送/接收源码:
关闭连接函数
遇到的问题
LWIP移植:
手动移植LWIP(裸机):
STM32H563 HAL库 LWIP裸机移植 (包含源代码 一文搞定 )_lwip 裸机-CSDN博客https://blog.csdn.net/weixin_67846820/article/details/137764818?spm=1001.2014.3001.5502基于CubeMX移植LWIP(裸机):
STM32F429及STM32H563 基于CubeMX HAL库LWIP裸机移植(超详细)_stm32cubemx lwip-CSDN博客https://blog.csdn.net/weixin_67846820/article/details/139880496?spm=1001.2014.3001.5502
TCP裸机编程:
使用lwip协议栈中的TCP通讯时,大部分都是需要回调函数。
注册回调函数后,协议栈会在适当时机自动调用该函数。
参考(官网API讲解链接):
lwIP: Overview
下面是注册回调函数的接口:
TCP客户端连接 RAW API:
API: | struct tcp_pcb *tcp_new(void); |
作 用: | 建立新的TCP控制块 |
参 数: | 无 |
返回值: |
pcb:成功建立了新的TCP控制块 NULL:建立控制块失败 |
API: |
err_ttcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected); |
作 用: | 主动向指定远程主机发送连接 |
参 数: |
pcb: 指定一个TCP控制块连接 ipaddr: 指定连接远程主机的IP port:指定连接远程主机的端口 connected:指定连接后调用的回调函数 |
返回值: |
ERR_OK:连接成功 其他:连接失败 |
API: | void tcp_err(struct tcp_pcb *pcb, tcp_err_fn err); |
作 用: | 指定处理错误后调用的回调函数 |
参 数: |
pcb: 指定需要处理错误的TCP控制块 err:指定错误发生时调用的回调函数 |
返回值: |
无 |
TCP客户端发起连接源码:
client_connected: 连接成功的回调函数
client_err: 连接异常的回调函数
#define DEST_IP_ADDR0 *** //对方IP
#define DEST_IP_ADDR1 ***
#define DEST_IP_ADDR2 ***
#define DEST_IP_ADDR3 ***
#define TCP_CLIENT_PORT *** //端口号
//TCP初始化
void TCP_Client_Init(void)
{
ip4_addr_t server_ip; //存放服务器IP
client_pcb = tcp_new(); //建立TCP控制块
IP4_ADDR(&server_ip, DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);//合并IP地址
//开始连接
tcp_connect(client_pcb, &server_ip, TCP_CLIENT_PORT, client_connected);
ip_set_option(client_pcb, SOF_KEEPALIVE);
//注册异常处理
tcp_err(client_pcb, client_err);
}
//连接成功回调函数
static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
return ERR_OK;
}
//连接错误回调函数
static void client_err(void *arg, err_t err)
{
//连接失败的时候释放TCP控制块的内存
//printf("closeconnect release\n");
//tcp_close(client_pcb); //关闭连接函数 在下方了解
//tcp_abort(client_pcb);
}
TCP客户端数据发送/接收函数 RAW API:
API: | err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags); |
作 用: | 将TCP数据写入缓冲区 |
参 数: |
pcb: 指定所要发送数据的TCP控制块 dataptr:准备发送的数据 len: 数据长度 copy:参数为TCP_WRITE_FLAG_COPY(1)时,数据将被分配到属于堆栈的内存中 参数为TCP_WRITE_FLAG_MORE(0)时,表示还有后续数据,这个标志表明可以延迟发送(适合发送大量分段数据时使用)。 |
返回值: |
ERR_OK:数据成功写入缓冲区 其他:写入失败 |
API: | void tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent); |
作 用: | 指定远程主机成功接收到数据后(发送数据成功后),调用的回调函数。 |
参 数: |
pcb: 指定与远程主机相连接的TCP控制块 sent:指定远程主机成功接收到数据后(发送数据成功后),调用的回调函数 |
返回值: |
ERR_OK:数据成功写入缓冲区 其他:写入失败 |
API: |
err_t tcp_output(struct tcp_pcb *pcb); |
作 用: | tcp_write() 只是将数据放入缓冲区,写入缓冲区后可以尝试使用tcp_output函数将缓冲区数据发送出去,但何时发送还是根据TCP底层逻辑。 |
参 数: |
pcb: 指定需要发送数据的TCP控制块 |
返回值: |
ERR_OK:数据成功发送 其他:发送失败 |
API: | void tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv); |
作 用: | 指定当有新的数据接收到时调用的回调函数 |
参 数: |
pcb: 指定所要接收数据的TCP控制块 recv:指定当新的数据接收到时调用的回调函数。 |
返回值: |
无 |
API: | void tcp_recved(struct tcp_pcb *pcb, u16_t len); |
作 用: | 当接收到数据时该函数必须被调用,用于获取接收到的数据的长度 |
参 数: |
pcb: 指定所要接收数据的TCP控制块 len:获取接收到的数据的长度 |
返回值: |
无 |
TCP客户端数据发送/接收源码:
连接成功回调函数后,注册接收回调函数。
//连接成功回调函数
static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{
//注册一个接收回调函数
tcp_recv(pcb,client_recv);
return ERR_OK;
}
//接受数据函数
static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
if (p != NULL)
{
//接收数据长度
tcp_recved(tpcb, p->tot_len);
//注册发送成功回调函数
tcp_sent(pcb, send_succeed_callback);
//返回接受到的数据
tcp_write(tpcb, p->payload, p->tot_len, TCP_WRITE_FLAG_COPY);
tcp_output(pcb);
}
return ERR_OK;
}
err_t send_succeed_callback(void *arg, struct tcp_pcb *tpcb,u16_t len)
{
//数据发送完成后的处理
return ERR_OK;
}
关闭连接函数
API: | err_t tcp_close(struct tcp_pcb *pcb); |
作 用: | 关闭一个指定的TCP连接,调用后会释放指定的tcp控制块 |
参 数: |
pcb: 指定所要关闭连接的TCP控制块 |
返回值: |
ERR_OK:连接正常关闭。 其他:连接关闭失败 |
API: | void tcp_abort(struct tcp_pcb *pcb); |
作 用: | 通过向远程主机发送RST(重置)段终止连接。pcb板被回收。这个函数永远不会失败。 |
参 数: |
pcb: 指定所要关闭连接的TCP控制块 |
返回值: | 无 |
遇到的问题
在使用TCP单次发送大量数据时发送不出去。
猜测是发送缓冲区满导致的,包括使用循环发送也是发送不出去。可以使用发送成功回调函数发送,当前数据发送完成后再次发送下一个组数据。
如果有问题或有更到的办法,欢迎探讨。
作者:梦途笑匠