IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> LwIP TCP Client 解决长数据发送的困扰 -> 正文阅读

[网络协议]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;
	}
	
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 23:16:55  更:2021-07-14 23:18:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 4:42:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码