uIP TCP/IP协议栈
转自yxwkaifa微博
第1章 uIP TCP/IP协议栈
uIP TCP/IP协议栈的目标是:即便是8位微控制器也可以使用TCP/IP协议栈进行网络通信。虽然小而简单, uIP不须要与他们通信的节点配有复杂,全尺寸协议栈,仅仅要通过执行轻量级协议栈可以通信便可。
代码仅仅有区区几k字节 。RAM消耗最低也仅仅有几百个字节。
1.1 uIP 介绍
传统的 TCP/IP 实现,其代码体积大占用资源多,对于8位或者16位的系统来说显得有点吃力。对于仅能容纳小于100k的系统。是不可能移植一个完整的TCP/IP协议栈的。
uIP设计仅仅实现了进行网络通信所需的必要的TCP/IP组件。
提供基础的UDP服务,重点是IP,ICMP(ping), TCP服务。uIP是用C语言编写的。
更多为小型系统设计的TCP/IP实现都假定嵌入式设备会和一个执行全尺寸TCP/IP协议栈的工作站级别的机器通信。
在这样的情形下。去除TCP/IP协议簇中非常少使用的功能模块成为可能。
1.2 TCP/IP 通信
协议的相关文档以RFC形式公布。看TCP/IP协议最权威的就是看RFC文档了。能够看看RFC1122文档,他定义了端到端的通信和模型中层与层之间的通信所应遵循的。
1.3 内存管理
uIP所针对的目标架构,其RAM都是稀缺的。这样TCP/IP协议栈能用到的RAM就很有限。或许就那么几K。
假设缓存满了。兴许的包就会丢弃。仅仅有当打开多个连接时,才可能出现这样的情形以致影响性能。原因在于uIP通告了一个非常小的接收窗体(窗体,协议中的概念),也就意味着每一个连接上仅仅有个TCP分组。
一旦TCP/IP报头生成并拷贝到全局缓存后。设备驱动就会发送出报头和数据(数据不是被一层层的协议头封装的么)。假设须要重传数据仅仅能又一次生成数据了。而不会有队列等待的。
仅有200字节RAM的设备上执行uIP也是能够的。仅仅是这样的配置极大的影响了网络的吞吐以及可同一时候在线的连接数。
1.4 应用程序接口 (API)
应用程序接口 (API) 定义了应用程序怎样和TCP/IP协议栈进行交互。
这样一来,繁重的任务管理以及上下文切换,任务栈分配对于uIP的目标群体来说是不现实的。也就是说BSD套接字对于uIP的不合适的。
相反,uIP使用事件驱动接口,有事件发生时相应的应用程序(UIP_APPCALL( ),如无标注下文中的应用程序均指UIP_APPCALL宏相应的函数)会被调用。
一个被实现为C函数执行在uIP顶层的应用程序会被uIP调用来响应特定的事件。就像telnet.h文件里的:
#define UIP_APPCALL telnetd_app
前文说了。uIP的目标架构起RAM都是非常少的,保存个副本等待反馈是不明智的。uIP的作法相同是把这事推给上层去做:应用程序负责生成数据并重传。
从应用程序角度看重传无异于数据原始发送。就是说重传的代码和发送数据的代码是可以复用的。虽然重传是应用程序进行的。但何时须要重传,协议栈必需负起责任。
1.4.1 应用程序事件
1.4.2 连接指针
一旦应用程序被uIP调用。全局变量uip_conn会指向表示当前连接的uip_conn结构(uip_connect()中会返回该结构)。
uip_conn结构中的域能够告知当前所连接的ip地址,以及通过uip_conn->lport来获得提供的服务。比方,假设lport为80则相应的是http服务;假设是23则是telnet服务。
1.4.3 接收数据
uIP通过调用uip_newdata()能够知道远程主机已经发送了新的数据。其长度能够通过调用uip_datalen()来获得。
uIP并不会缓存数据,并且一旦从应用程序返回,数据就会被覆盖。因此。应用程序要么直接处理到来的数据,要么拷贝到其它什么地方去稍后处理。
1.4.4 发送数据
当发送数据时。uIP会依据可利用buffer大小以及TCP窗来调节应用程序发过来的数据。通过uip_mss()函数来获得当前连接所能传输的最大分组大小。
在uip协议栈中。是怎样传递给驱动层的呢?由于uip_buff是全局的,这样驱动直接就调用dev_send_data(uip_buff,len);把数据发送出去了。
在一个连接上,应用程序一次仅仅能发送一块数据,在数据发送完毕前,同一时候对uip_send()进行多次调用时不可能的。
1.4.5 数据重传
if(uip_rexmit()|| uip_newdata() || uip_acked()) {
1.4.6 关闭连接
也可通过调用uip_abort()函数来终止产生了致命错误的连接:
假设连接已由远端关闭,uip_closed()返回1,应用程序可能会做必要的清理。
1.4.7 差错报告
uIP通过uip_aborted()和uip_timeout()来測试是否发生了对应的错误。
1.4.8 轮询
当连接处于空暇状态时,uIP会周期的轮询各个应用程序。应用程序则通过uip_poll()来检測是否正在被uIP轮询。轮询就採取动作。
1.4.9 监听port
检查uip_conn结构中lport域能够知道哪个端口和当前连接相相应。
这个过程是在uip_connect(*ripaddr,rport)函数中完毕对uip_conn结构赋值。并建立一个连接:通过找一个未使用的最小的端口号赋给lport,就实现和rport相应。
1.4.10 打开连接
由于uIP用包括俩个16bit元素的数组来表示一个32位的ip地址,使用uip_ipaddr()能够用来封装一个ip地址到2个16位的。
以下展示了两个样例,第一个展示了使用uip_connect()尝试建立一个到TCPport号为8080的连接,假设达到最大连接数,则其返回NULL。而且使用uip_abort()来中止当前连接。
void connect_example1_app(void) {
if(uip_connect(uip_conn->ripaddr,HTONS(8080)) == NULL) {
第二个样例展示了怎样打开一个到指定ip地址的连接,该例中没有进行错误检查。
uip_ipaddr(ipaddr, 192,168,0,1);
uip_connect(ipaddr, HTONS(8080));
1.5 uIP设备驱动
从网络设备驱动角度看。如图1-5,uIP由uip_input()和uip_periodic()这两个C语言函数组成。
uip_input()和uip_periodic()都是对uip_process(arg)的调用;
1.6 架构相关的函数
uIP要求那些打算执行uIP的目标架构须要实现架构相关的函数。
uIP代码中也提供了一些通用的C实现函数。在uip-arch.c文件里实现了简单的CRC校验。
1.6.1 校验和计算
TCP和IP协议为TCP和IP的数据和协议头包实现了校验和。
uIP发行版中提供了一个用C语言实现的校验和计算函数。相同是在uip-arch.c文件里。
1.6.2 32位运算
架构相关的代码中必需实现uip_add32()这个用来进行32位加法的函数,其结果存储在uip_acc32这个全局变量中了。
1.7 实例
这一小节中介绍一些很easy的uIP应用程序,在uIP发行包中包括了一些更复杂的应用。telnet,smtp等等。
1.7.1 一个很easy的应用程序
第一个简单的应用程序用来监听1234port上的连接。一旦连接建立完毕,他会用“ok”来应答全部发给他的数据。
void example1_init(void) { // 初始化函数
uip_listen(HTONS(1234)); // 在port1234上监听
// #define UIP_APPCALL example1_app
if(uip_newdata() || uip_rexmit()) { //有新数据要发送或者须要重传了
初始化函数调用uIP的uip_listen()函数来注冊一个要监听的port号。应用程序example1_app()用uip_newdata()和uip_rexmit()来推断被调用的原因。
假设是连接还有一端发送了数据,就用“ok”来应答。假设是数据丢失须要重传也用“ok”进行应答。
并没有限定应用程序必须实现全部的事件类型比方uip_connected()或者uip_timedout()。
1.7.2 一个高级应用
第二个样例展示了uip_conn结构体中应用程序状态域是怎样使用的。
和第一个样例相似,当监听的port上有数据发来时就用“ok”进行应答。
最大的差别在于,第二个样例还会在连接建立完毕时输出一个“Welcome。”。
虽然看上去没啥差别。可是这一点细微的变化却相应用程序的实现产生了不小的影响。
复杂度添加的原因在于假设网络中的数据丢失了,应用程序必须知道哪个数据须要重传。假设是“Welcome!”消息丢了,应用程序必须重传welcome,假设是“ok”丢了。就得又一次发送ok。
假设远程主机没有对“Welcome。”作出应答。应用程序可一断定数据丢读了。可是一旦主机作出应答就能够确信丢掉的数据是“ok”。
这样应用程序就处在俩中状态之中的一个:WELCOM-SENT,welcome已经发出去,可是没有收到应答。WELCOME-ACKED,发送成功且收到应答。
当远端主机成功连接到应用程序。应用程序会发送“Welcome!”而且把自身状态设置成WELCOME-SENT。当远端主机应答成功,状态变成WELCOME-ACKED。
假设请求应用程序重传上一个消息。应用程序首先看一下他的状态,假设是WELCOME-SENT,他就知道welcome发送出去了可是没有收到应答,该重传的是“welcome!
假设处在WELCOME-ACKED状态,则须要重传的是”ok“。
应用程序实现例如以下,一些配置信息紧随其后(一个简单的状态机):
enum{WELCOME_SENT, WELCOME_ACKED} state;
s= (struct example2_state *)uip_conn->appstate;
if(uip_acked()&& s->state == WELCOME_SENT) {
#define UIP_APPCALL example2_app
#define UIP_APPSTATE_SIZE sizeof(structexample2_state)
1.7.3 怎样区分不同的应用程序
假设一个系统要执行多个应用时,区分他们做好的方法就是用TCPport号。
1.7.4 使用TCP流量控制
以下的样例展示了向一个主机发送HTTP请求下载文件到一个慢速的存储设备上。怎样使用流量控制功能:
uip_ipaddr(ipaddr,192,168,0,1);
uip_connect(ipaddr,HTONS(80));
if(uip_connected()|| uip_rexmit()) {
uip_send("GET/file HTTP/1.0\r\nServer:192.186.0.1\r\n\r\n", 48);
device_enqueue(uip_appdata,uip_datalen());
uip_stop();// 这里仅仅是设置了tcpstateflag标志位而已
if(uip_poll()&& uip_stopped()) { // 推断是轮询且之前是被停止的
if(!device_queue_full()){ // 队列未满则重新启动连接
1.7.5 简单的webserver
以下的代码是一个简单的文件server,其监听2个port,依据port号来选择发送哪个文件:
s = (structexample5_state)uip_conn->appstate;
uip_send(s->dataptr,s->dataleft);
uip_send(s->dataptr,s->dataleft);
程序状态由数据指针和要发送数据大小两部分组成。这里的appstate[UIP_APPSTATE_SIZE]非常像驱动中的*private_data结构用于存储设备相关的结构体。
1.7.6 结构化应用程序设计
if(uip_connected()) { // 已建立连接
if(uip_newdata()) { // 处理新数据,设置要发送数据指针
if(uip_rexmit() || uip_newdata() || //重传、有新数据、应答、已连接、轮询?发送数据
uip_acked()||uip_connected() || uip_poll()) {
接下来的代码,告诉我们上面用到的一些处理函数其形式大概是啥样子的:应用简单的等待连接上的数据到达,并通过发送“Hello World!”来应答。
而且,为了展示怎样编写状态机。消息被拆分成俩部分进行发送:“Hello”和“World!”:
struct example6_state{ // 程序状态变量
struct example6_state *s = (structexample6_state *)uip_conn->appstate;
struct example6_state *s = (structexample6_state *)uip_conn->appstate;
if(s->state == STATE_WAITING) {
struct example6_state *s = (structexample6_state *)uip_conn->appstate;
struct example6_state *s = (structexample6_state *)uip_conn->appstate;
uip_send(s->textptr,s->textlen);
真正进行数据发送的是senddata()函数。acked()和newdata()仅仅是标识有数据须要发送,其长度是多少。
senddata()终于回调用uip_send()来发送数据。
切记senddata()函数永远不能做改变应用程序状态的事。相反这些应该在acked()和newdata()进行。
uIP TCP/IP协议栈相关推荐
- uIP TCP/IP协议栈在51系列单片机上的应用
uIP 协议栈是一种免费的可实现的极小的TCP/IP协议栈,可以使用于由8位或16位微处理器构建的嵌入式系统.本文分析了uIP协议栈的结构和应用接口,并讨论了如何将其应用到51系列单片机上. 关键字: ...
- TCP/IP协议栈在MSP430单片机上的实现
引言 随着信息技术的不断发展,以及人们对日常生活舒适度.方便度要求的提高,信息家电.智能仪表等产品越来越频繁的出现在我们的生活当中:人们也越来越热衷于把家电.仪表等设备连接到Internet 中,从而 ...
- 几种开源的TCP/IP协议栈分析
1.BSD TCP/IP协议栈 BSD栈历史上是其他商业栈的起点,大多数专业TCP/IP栈(VxWorks内嵌的TCP/IP栈)是BSD栈派生的.这是因为BSD栈在BSD许可协 议下提供了这些专业栈的 ...
- 单片机tcp ip协议c语言,单片机TCP IP协议栈实现的原理
对已TCP IP协议栈,我们已经说了很多关于它的原理相关的知识了.但是只有原理是不够的,在这方面我们将要举出一个实际操作实例为大家讲解,那么首先我们来看一下有关于单片机TCP/IP就是在单片机上运行的 ...
- STM32F103驱动SDIO wifi Marvell8801/Marvell88w8801 介绍(十) ---- 移植TCP/IP协议栈LWIP
代码工程的GITHUB连接:点进进入GITHUB仓库 https://github.com/sj15712795029/stm32f1_marvell88w8801_marvell8801_wifi ...
- 源码公开的TCP/IP协议栈在远程监测中的应用
目前,随着互联网的发展,越来越多的工业测控设备已经将网络接入功能作为其默认配置,以实现设备的远程监控和信息分布式处理.笔者曾参与某发电机射频监测仪的开发,该设备主要用于诊断和预警发电机早期故障,并通过 ...
- uIP tcp/ip协议分析及其在嵌入式系统中的应用
网络技术的发展使越来越多的工业控制设备将网络接入功能作为其必备的特性之一.同样,嵌入式系统的发展,要求其应用能够支持网络功能,为用户提供一个简易方便的可视化图形界面.当前WEB浏览器已经成为用户的合理 ...
- 几种开放源码的TCP/IP协议栈比较
http://blog.chinaunix.net/uid-28785506-id-3828286.html 原文地址:几种开放源码的TCP/IP协议栈比较 作者:三点水兽 1.BSD TCP/IP协 ...
- TCP/IP 协议栈4层结构及3次握手4次挥手
TCP/IP 协议栈是一系列网络协议的总和,是构成网络通信的核心骨架,它定义了电子设备如何连入因特网,以及数据如何在它们之间进行传输.TCP/IP 协议采用4层结构,分别是应用层.传输层.网络层和链路 ...
最新文章
- 你所知道及不知道的骗贷、中介、欺诈团伙是怎么样的
- 结巴分词优点_中文分词概述及结巴分词原理
- python调用C语言函数(方法)的几种方法
- ES5中的有9个Array方法
- python wordpress建站_WordPress快速建站
- 整理好的200多java面试题,可用于机器学习
- 云主机挂载硬盘 - 开机自动挂载
- 在VS2008中使用jQuery智能感应
- 想做程序员?不同方向入门路线全解
- 三级联动插件distpicker
- 5号字对应的数字字号_五号字体是多少磅的?
- 使用cmd命令清空windows中C盘的所有临时文件
- php 微信 语音,微信语音的上传与下载功能实现详解
- ava.lang.IllegalArgumentException: At least one base package must be specified 	at org.springframewo
- xmanager登陆linux黑屏,用xmanager软件登陆linux的方法
- intellij 打开两个窗口
- 实例分割向:Mask R-CNN
- 体验Google Plus
- Swarm管理Docker集群
- 青龙面板快手极速版教程
热门文章
- 曾国藩:从30岁起,脱胎换骨
- 浮云E绘图SDK3.0,快速开发电路图、电子图纸、工业控制流程图、工艺流程图等绘图项目
- 魁拔妖侠传 之 浮云骑士语录
- 【git】No supported authentication methods available(server sent:pubickey)
- 【获取路径grob()】学习笔记
- 【提交】commit
- 专业音频如何把电平转换成dbu_正确理解音频设备的电平信号
- vscode实现边写边查
- 4.2网际协议IP(IPv4)
- 计算机一级outlook百度云,Outlook2010官方版