LwIP TCP Client 解决长数据发送的困扰

问题描述

LWIP 的 TCP Client 发送数据可以调用 tcp_write() 函数,将数据储存在缓冲区里面,然后等待超时自动发送或者调用tcp_output()函数进行发送。

然而 tcp_write() 函数 需要发送的数据过长时,将无法发送,并返回 ERR_MEM。

tcp_write()函数解析

tcp_write()的函数代码很多,就不细看代码了,

先看tcp_write()的完整函数:

err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)

其中 pcb 是TCP协议块
arg 是待发送数据指针
len 是待发送数据长度
apiflags 是发送的方式,如果是1,则发送的时候,会复制数据到缓存进行发送,如果是2,则发送过程中arg的数据不能变化

如何解决发送长度的问题

看官方注释:

 * The proper way to use this function is to call the function with at
 * most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
 * the application should wait until some of the currently enqueued
 * data has been successfully received by the other host and try again.

翻译过来的意思就是:
使用此函数的正确方法是使用最多tcp_sndbuf()字节的数据调用该函数。如果函数返回ERR_MEM,应用程序应该等待,直到当前排队的数据被其他主机成功接收,然后再试一次。

其中tcp_sndbuf() 是一个宏定义, 最终是指pcb结构体里的 tcpwnd_size_t snd_buf;
/* Available buffer space for sending (in bytes). */
也就是一次发送的最大字节数。

由此可知,我们发送长数据的时候,只需要连续分包发送,且每次发送小于tcp_sndbuf()字节,就可以实现长数据发送了

最终实现长数据发送函数

最后附上已实现的函数,配合FREERTOS,就可以发送长数据了,实测稳定可用。

int my_tcp_write_eth(uint8_t * Buf,int Size)
{
	int try_time = 0;
	
	int send_pack_index = 0;
	
	if(Size == 0)
		return 0;
	
	err_t err_status;
	
	int sizemax = 500;//tcp_sndbuf(client_pcb);
	
	send_pack:
	
	if(try_time >= 150)
	{
		printf("TCP发送失败! ERR_MEM \n");
		return -1;
	}

	if(Size == 0)
		return 1;
	if(Size <= sizemax)
	{
		err_status = tcp_write(client_pcb, &Buf[send_pack_index * sizemax], Size , 1);
		
		if(err_status != ERR_OK)
		{
			if(err_status == ERR_MEM)
			{
		//		printf("TCP发送失败!数据太长%u\n",Size);		
				osDelay(5);
				try_time ++;
				goto send_pack;
			}
			else
				printf("TCP发送失败!\n");
				//tcp_err(client_pcb, client_err); 	
			return -1;
		}
		
			//立刻发送
			if(tcp_output(client_pcb) != ERR_OK)
			{
				printf("TCP发送失败!\n");
				return -1;	
			}
		
		return 1;
	}
	else
	{
		  //printf("数据大于sizemax,分包发送! %u\n",send_pack_index);
		
			err_status = tcp_write(client_pcb, &Buf[send_pack_index * 500], 500, 1);
			
			if(err_status != ERR_OK)
			{
				if(err_status == ERR_MEM)
				{
				//	printf("TCP发送失败!数据太长%u\n",Size);
					osDelay(5);
					try_time ++;
					goto send_pack;
				}
				else
					printf("TCP发送失败!\n");
					//tcp_err(client_pcb, client_err); 	
				return -1;
			}
			
			//立刻发送
			if(tcp_output(client_pcb) != ERR_OK)
			{
				printf("TCP发送失败!\n");
				return -1;	
			}
			
			
			try_time = 0;
			
			
			Size -= sizemax;
			
		//	printf("发送完成! 剩余 %u 字节需要发送\n",Size);
			
			send_pack_index ++;
			
			goto send_pack;
	}
	
}
  • 7
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值