基于uIP和uC/OS-II嵌入式网络开发
基于uIP和uC/OS-II嵌入式网络开发
——uIP主动发送数据分析
摘要:uIP协议栈简单易用,可以为16位单片机或者是更低级的处理器使用,占用的资源很少,相关移植网上有详细介绍,本文主要讨论uIP如何主动发送数据。所用的开发板是STM32系列的,uC/OS-II操作系统,开发板作为服务器端。
关键字:uIP;uC/OS-II;STM32
1 系统要实现的功能
主要功能如下:
开发板作为服务器端,PC做客户端。连接成功以后,服务器始终作为主动的一方,主动与PC发送数据,PC收到后回传数据帧给服务器。服务器不给PC交互数据时,则认为是空闲的,这时需要以3秒的频率给PC发送心跳,维持连接。
系统主要任务如下:
心跳任务:负责心跳的发送,3秒到了,如果服务器不在给PC交互数据中,则主动发送心跳帧给PC机;
网络数据接收任务:负责轮询的方式接收数据,OSTimeDly(1),1毫秒轮询一次,在这个任务中也处理500毫秒ARP超时和10秒TCP超时。收到数据以后交给协议栈处理,协议栈调用应用程序回调函数tcp_demo_appcall,判断是否新数据到来,若是则调用newdata()。在newdata()函数中处理PC发送过来的数据,并通过发送信号量的方式与主任务交互。
主任务:负责与PC的数据交互,合适的时机主动发送数据给PC机,然后通过信号量等待PC客户端的数据,等到以后再传下一包数据。
2 需要解决的问题
2.1 客户端多次重连
UIP协议栈默认提供20个用于listen状态的tcp结构,10个用于连接状态的tcp结构。这样服务器端可以处理多个客户端,现在考虑的是,服务器端只希望处理一个客户端。而客户端连接服务器的时候,不管现在服务器是否已经有客户端连接了,这样就需要服务器在收到新的客户端连接时,若已经与前一个客户端建立连接,需要先将其断开,然后再与这个新的建立连接。
2.1.1 若客户端主动关闭连接,这样很好理解
先看连接过程,3次握手:
UIP_CLOSED收到客户端的连接SYN,则变为UIP_SYN_RCVD,并给客户端发送SYN+ACK,收到客户端的ACK,则变为UIP_ESTABLISHED,表明建立了连接。
关闭过程:
UIP_ESTABLISHED,收到客户端的FIN,变为UIP_LAST_ACK,并给客户端发送FIN+ACK,
收到客户端的ACK,则变为UIP_CLOSED,标示已经断开了连接。
2.1.2 客户端不断开原来的连接,直接来新连接
鉴于上面的分析,此时有两种办法,在程序回调函数tcp_demo_appcall中,判断是连接,然后调用connected函数。
(1)服务器不管客户端,直接自己释放资源,代码如下:
这是方式是,客户端没有执行断开连接,服务器端也没有执行断开连接,服务器端只是单方面释放了自已占用的资源。
(2)服务器端主动关闭与客户端的连接,然后在与新的客户端连接,主要代码如下:
执行pool推送以后,协议栈调用调用回调函数,进行判断,代码如下:
2.2 主动发送数据
网口接收数据任务,收到数据后,交给协议栈处理。协议栈通过发送信号量的方式与主任务同步,这样主任务就可以发送下包数据。这样的流程,前提是网口接收数据任务优先级低,主任务可以在250毫秒内发送应用数据给客户端,若等待网口接收数据任务将ACK包发送给客户端以后,此时主任务再发送数据就算是主动发送了。
Uip协议栈提供了一个poll功能,可以这种方式主动发送数据,主要代码如下:
需要发送数据时,先调用uip_send将数据拷贝到uip_buf缓存,然后利用pool功能,获取要发送数据的IP首部和TCP首部,最后再组建MAC的14个字节,最终通过调用物理层函数实现数据发送。下面讨论主动发送数据带来的问题。
2.2.1 数据冲撞
发送心跳的任务与主任务都在运行,不能保证两者不发生碰撞,实际测试中存在这样一种状况,心跳数据包刚发送完,250毫秒内客户端没有ACK,但此刻主任务也要发送数据,造成冲撞,如下图所示,分析这一过程。
9118序号:这是发送的一个长度为11的心跳包,tcp块结构的发送序列号是230;
9120序号:183毫秒后主任务发送长度为38的数据帧,但是tcp快结构的发送序列号仍然是230;
9121序号:客户端认为这样的发送有误,TCP ACKed unseen segment。
实际客户端的应用层数据收到的数据是这样的,
FF FF 38 B2 00 00 00 00 80 0A FF
BE A9 B1 B1 BE A9 00 00 00 00 00 00 00 01 20 08 01 01 20 10 12 31 10 02 00 AA FF
第一个包是长度为11的心跳包,但是第二包的长度变为了27,即来到应用层的数据被截断了,协议栈把前面的11个字节给扔掉了。
2.2.2 稍加改进
找到了问题的原因,则试图进行改进,主动发送数据时,自定义变量保存这次要发送的数据长度,然后收到客户端对这包数据的ACK时清0。主动发送数据时,判断之前发送的数据是否都被ACK了,若有数据未被ACK,则将tcp块结构的发送序列号增加,实现的主要代码如下图所示。
使用这种方式随然可以避免数据被截断的问题,但是其它的问题还会出现。我发现的就有两个,一是收不到上位机的数据,非要等上位机重发,这样会造成时间的浪费,如下图所示。
84834:客户端已经发送了数据,但是收不到服务器端的ACK,将近300毫秒后,客户端重发这包数据,此时才收到服务器端的ACK。
二是上位机收不到服务器端的数据,但是服务器也不会超时重传,这样就会卡到这里,如下图所示。
145649:服务器端发送的数据,序列号是36996;
145660:收到客户端的ACK,ACK的是36977;
145567:服务器直接从37015开始发送数据,中间正好丢失一个长度为38的数据,下面客户端反复说明之前的一包没有收到,但是服务器端就是没有重传。
3 总结
由上看出,将UIP移植到操作系统以后,可以使用,但是UIP将发送和接收的数据都保存在一个缓存uip_buf中,且发送和接收数据的长度也都是一个变量len,这样会出现一些问题。对于超时重传等,我没有找到合适的解决办法,考虑到UIP和LWIP是同一个团队编写的,直接采用LWIP开发。
基于uIP和uC/OS-II嵌入式网络开发的更多相关文章
- uC/OS II原理分析及源码阅读(一)
uC/OS II(Micro Control Operation System Two)是一个可以基于ROM运行的.可裁减的.抢占式.实时多任务内核,具有高度可移植性,特别适合于微处理器和控制器,是和 ...
- 【原创】uC/OS II 任务切换原理
今天学习了uC/OS II的任务切换,知道要实现任务的切换,要将原先任务的寄存器压入任务堆栈,再将新任务中任务堆栈的寄存器内容弹出到CPU的寄存器,其中的CS.IP寄存器没有出栈和入栈指令,所以只能引 ...
- 【小梅哥SOPC学习笔记】NIOS II处理器运行UC/OS II
SOPC开发流程之NIOS II 处理器运行 UC/OS II 这里以在芯航线FPGA学习套件的核心板上搭建 NIOS II 软核并运行 UCOS II操作系统为例介绍SOPC的开发流程. 第一步:建 ...
- uC/OS II 函数说明 之–OSTaskCreate()与OSTaskCreateExt()
1. OSTaskCreate() OSTaskCreate()建立一个新任务,能够在多任务环境启动之前,或者执行任务中建立任务.注意,ISR中禁止建立任务,一个任务必须为无限循环结构. ...
- uc/os iii移植到STM32F4---IAR开发环境
也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...
- 关于uC/OS的简单学习(转)
1.微内核 与Linux的首要区别是,它是一个微内核,内核所实现的功能非常简单,主要包括: 一些通用函数,如TaskCreate(),OSMutexPend(),OSQPost()等. 中断处理函数, ...
- 【RL-TCPnet网络教程】第1章 当前主流的小型嵌入式网络协议栈
第1章 当前主流的小型嵌入式网络协议栈 这几年物联网发展迅猛,各种新产品.新技术也是层出不穷,本章节就为大家介绍当前主流的小型嵌入式网络协议栈. 1.1 当前主流的嵌入式网络协议栈 1.2 u ...
- 【RL-TCPnet网络教程】第2章 嵌入式网络协议栈基础知识
第2章 嵌入式网络协议栈基础知识 本章教程为大家介绍嵌入式网络协议栈基础知识,本章先让大家有一个全面的认识,后面章节中会为大家逐一讲解用到的协议. 基础知识整理自百度百科,wiki百科等 ...
- LwIP协议栈开发嵌入式网络的三种方法分析
LwIP协议栈开发嵌入式网络的三种方法分析 摘要 轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...
随机推荐
- Filter内容
1.利用Filter来过滤的时候大都是Http请求和Http响应,在doFilter()方法中,参数类是ServletRequest和ServletResponse ,使用的时候一般需要强制转换为H ...
- 七 FileChannel
FileChannel是一个连接到文件的通道,可以通过文件通道读写文件 FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下. 打开FileChannel 在使用FileChannel之 ...
- pyhton基础中的要点一
1.python变量的命名规范: (1)变量必须以数字,字母,下划线的任意组合 (2)变量建议用驼峰标识,或下划线 (3)变量要有可描述性 (4)不能以数字开头 (5)不能用python的关键字 (6 ...
- ccf-201809-2 买菜
问题描述 小H和小W来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买n种菜,所以也都要装n次车.具体的,对于小H来说有n个不相交的时间段 ...
- BFC(Box Formatting Context)的原理
BFC 已经是一个耳听熟闻的词语了,网上有许多关于 BFC 的文章,介绍了如何触发 BFC 以及 BFC 的一些用处(如清浮动,防止 margin 重叠等).虽然我知道如何利用 BFC 解决这些问题, ...
- hihoCoder 1148 2月29日
时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: ...
- 函数arguments对象
一.arguments对象 arguments 是一个对应于传递给函数的参数的类数组对象. 二.语法 arguments 三.描述 arguments对象是所有(非箭头)函数中都可用的局部变量.你可以 ...
- react 反模式——不使用jsx动态显示异步组件
前言: react反模式 (anti-patterns)指的是违背react思想(flux)的coding方式. 本文在 App 组件中,通过 Model.show 动态显示 Model 组件,通过 ...
- linux定时备份MySQL数据库并删除七天前的备份文件
1.创建备份文件夹 #cd /bak#mkdir mysqldata 2.编写运行脚本 #nano -w /usr/sbin/bakmysql.sh 注:如使用nano编辑此代码需在每行尾添加’&am ...
- Mysql学习---全国省市区以及邮编数据库
更多下载