Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread一般讨论
实战分析:TCP/IP
发布于 2013-07-15 19:39:22 浏览:2437
订阅该版
这是一篇新手贴,希望能帮到同样探索在LWIP或TCP/IP道路上初学者朋友们。 老看书,总会有种云里雾里的感觉,比如:以太网的数据包到底是怎样的?ICMP什么情况下会发送? TCP的序号和确认序号到底是怎么回事?TCP连接的建立三次握手、终止四次握手在实际数据包中是怎样的? 相信这些你一定会感兴趣。 若是STM32+DM9000的网卡,参考stm32f10x的bsp,修改一下DM9000a.c的内容,在 rt_err_t rt_dm9000_tx( rt_device_t dev, struct pbuf* p)这个函数里找到发送部分的代码, 发送数据时把将数据打印出来 ``` while (q) { if (pbuf_index < q->len) { DM9000_TRACE("%02x ", ((u8_t*)q->payload)[pbuf_index]); word[word_index++] = ((u8_t*)q->payload)[pbuf_index++]; if (word_index == 2) { DM9000_outw(DM9000_DATA_BASE, (word[1] << 8) | word[0]); word_index = 0; } } else { q = q->next; pbuf_index = 0; } } /* One byte could still be unsent */ if (word_index == 1) { DM9000_outw(DM9000_DATA_BASE, word[0]); DM9000_TRACE("%02x ", word[0]); } DM9000_TRACE(" "); ``` 接收部分也一样地加一下,别忘了在dm9000a.c的起始打开宏DM9000_DEBUG ``` #define DM9000_DEBUG 1 ``` 如果你手上有Realtouch就更简单了,找个LWIP打开的realtouch例程,找到stm32f4xx_eth.c,打开三个宏就可以了 #define ETH_DEBUG #define ETH_RX_DUMP #define ETH_TX_DUMP 编译、下载重启! 可以看到 ``` | / - RT - Thread Operating System / | 1.1.0 build Jul 13 2013 2006 - 2012 Copyright by rt-thread team rtc is not configured please configure with set_date and set_time Nor Flash ID:0xbf 0x2782 dm9000 id: 0x90000a46 finsh>>operating at 100M full duplex mode dm9000 tx: len 42 ff ff ff ff ff ff 00 60 6e 21 22 33 08 06 00 01 08 00 06 04 00 01 00 60 6e 21 22 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 dm9000 tx: first packet dm9000 isr: int status 0001 dm9000 isr: int status 0002 dm9000 tx done TCP/IP initialized!``` 当然,还有收到一大堆电脑发过来的数据,那些我们暂时不管它,捡主要的说。(后来我也分析了一下主要是udp138端口或者udp137端口的广播包) 这个数据包只一lwip一启动就会发送。参照tcp/ip协议对照一下很容易分析: ``` ff ff ff ff ff ff 00 60 6e 21 22 33 08 06 //这是以太网包头,可以看出这是一个广播ARP包 00 01 //硬件类型:以太网 08 00 //协议类型:IP 06 //硬件地址长度:6(六字节的物理地址) 04 //协议地址长度:4(四字节的IP地址) 00 01 //操作类型: ARP请求 00 60 6e 21 22 33 //发送端物理地址 00 00 00 00 //发送端IP 00 00 00 00 00 00 //目的物理地址 00 00 00 00 //目的IP ``` 以上共42字节,细心的你会发现是不对的,ARP包里18字节填充和4字节的CRC跑哪儿去了?这是DM9000自动完成了。 因为DM9000每包数据的发送至少会是64字节,不够的会自己填充,还会加上CRC,所以不用我们自已做软件CRC了。 好了,我们ping一下看看: ``` dm9000 isr: int status 0001 dm9000 rx: status 4001 len 64 ff ff ff ff ff ff 08 9e 01 65 4a c5 08 06 00 01 08 00 06 04 00 01 08 9e 01 65 4a c5 0a 1e 1d 64 00 00 00 00 00 00 0a 1e 1c 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 1f 6a 02 dm9000 tx: len 64 08 9e 01 65 4a c5 00 60 6e 21 22 33 08 06 00 01 08 00 06 04 00 02 00 60 6e 21 22 33 0a 1e 1c 21 08 9e 01 65 4a c5 0a 1e 1d 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 1f 6a 02 dm9000 tx: first packet dm9000 isr: int status 0002 dm9000 isr: int status 0001 dm9000 tx done dm9000 rx: status 0001 len 78 00 60 6e 21 22 33 08 9e 01 65 4a c5 08 00 45 00 00 3c 03 81 00 00 40 01 29 80 0a 1e 1d 64 0a 1e 1c 21 08 00 4d 5a 00 01 00 01 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 69 8c fb 1e 01 dm9000 tx: len 74 08 9e 01 65 4a c5 00 60 6e 21 22 33 08 00 45 00 00 3c 03 81 00 00 ff 01 6a 7f 0a 1e 1c 21 0a 1e 1d 64 00 00 55 5a 00 01 00 01 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 69 dm9000 tx: first packet dm9000 isr: int status 0002 dm9000 tx done ``` 一收一发这里姑且称之为一次会话,Ping程序共引发了5次会话。(后面还有三次会话,与第二次会话几乎一样,就没列出数据,占地方) 显然,第一次会话是ARP请求和应答,因为一开始PC机的ARP缓存里是没我们板子的地址信息的。 第二次会话至第五次会话对应ping命令发送的四次数据包,分析一下: ``` PC->DM9000: 00 60 6e 21 22 33 08 9e 01 65 4a c5 08 00 //以太网包头,IP包 45 00 00 3c 03 81 00 00 40 01 29 80 0a 1e 1d 64 0a 1e 1c 21 //IP首部,第10字节0x01指示这是一个ICMP包 08 00 4d 5a 00 01 00 01 //ICMP首部:类型代码0x0800指示,这是一个请求回显,即Ping请求 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 69 //用户数据 8c fb 1e 01 //以太网包的CRC校验 DM9000->PC 08 9e 01 65 4a c5 00 60 6e 21 22 33 08 00 //以太网包头,IP包 45 00 00 3c 03 81 00 00 ff 01 6a 7f 0a 1e 1c 21 0a 1e 1d 64 //IP包头,第10字节0x01表明这是一个ICMP包 00 00 55 5a 00 01 00 01 //ICMP首部,类型代码0x0000指示这是一个回显应答 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 69 //用户数据 32字节 ``` 可以看出,DM9000在接收时,CRC校验字节是带上的,这就需要软件CRC了。不同的网卡CRC的处理是不一样的,像STM32F407可以 接收发送都可以硬件CRC(我的F407板子上没有看到),而DM9000发送可以硬件CRC,接收就不是了。 好了,由简入繁,再看看UDP。 首先还是写个UDP的代码: ``` #include
#include "lwip/api.h" #include
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t udp_client_stack[ 1024 ]; static struct rt_thread udp_client_thread; static void udp_client_thread_entry(void* parameter) { const unsigned char welcome[] = "hello, world! "; struct netconn *new_conn; struct netbuf *buf; struct ip_addr addr; IP4_ADDR(&addr,10,30,28,100); buf = netbuf_new(); netbuf_ref(buf,welcome,sizeof(welcome)); new_conn = netconn_new(NETCONN_UDP); netconn_bind(new_conn,NULL,56795); netconn_connect(new_conn, &addr, 2001); netconn_send(new_conn, buf); netbuf_delete(buf); netconn_delete(new_conn); } int udp_client(void) { rt_err_t result; result = rt_thread_init(&udp_client_thread, "udp_cl", udp_client_thread_entry, RT_NULL, (rt_uint8_t*)&udp_client_stack[0], sizeof(udp_client_stack), 20, 5); if (result == RT_EOK) { rt_thread_startup(&udp_client_thread); } return 0; } #ifdef RT_USING_FINSH #include
FINSH_FUNCTION_EXPORT(udp_client, creat UDP client thread.) #endif ``` finsh下执行udp_client() ``` finsh>>udp_client() 0, 0x00000000 dm9000 tx: len 42 ff ff ff ff ff ff 00 60 6e 21 22 33 08 06 00 01 08 00 06 04 00 01 00 60 6e 21 22 33 0a 1e 1c 21 00 00 00 00 00 00 0a 1e 1c 64 dm9000 tx: first packet dm9000 isr: int status 0002 dm9000 isr: int status 0001 dm9000 tx done dm9000 rx: status 0001 len 64 00 60 6e 21 22 33 08 9e 01 65 4a c5 08 06 00 01 08 00 06 04 00 02 08 9e 01 65 4a c5 0a 1e 1c 64 00 60 6e 21 22 33 0a 1e 1c 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 9f bf 9c dm9000 tx: len 58 08 9e 01 65 4a c5 00 60 6e 21 22 33 08 00 45 00 00 2c 00 01 00 00 ff 11 6e ff 0a 1e 1c 21 0a 1e 1c 64 dd db 07 d1 00 18 61 f7 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0d 0a 00 dm9000 tx: first packet dm9000 isr: int status 0002 dm9000 isr: int status 0001 dm9000 tx done ``` 同样,第一次会话是Dm9000的ARP请求,同上。我们只看第三包数据: ``` 08 9e 01 65 4a c5 00 60 6e 21 22 33 08 00 //以太网包头,IP包 45 00 00 2c 00 01 00 00 ff 11 6e ff 0a 1e 1c 21 0a 1e 1c 64 //IP首部,第10字为0x11=17,UDP包 dd db 07 d1 00 18 61 f7 //8字节的UDP首部 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0d 0a 00 //用户数据"hello world! " ``` 可以看出: (1)UDP的IP首部中协议字段为0x11,而TCP为0x06,IP层会根据这个字段决定是将数据据交给TCP还是UDP。 虽然都有端口号这样的说法,但是它们相互独立的。例如:TCP的2000端口与UDP的2000端口没有任何联系。 如果有,也是使用的方便,而不是协议的要求(见TCP/IP 详解卷1第107页) (2)UDP是直接发数据的,没有建立连接这样的概念,也不需要ACK确认,因为我们没有看到相关的回应帧。 即使对方的端口没有打开,也是可以发成功的。不过这时你会收到另一个数据包,下面是我的2001端口没有打开时的情况: ``` finsh>>udp_client() 0, 0x00000000 dm9000 tx: len 58 08 9e 01 65 4a c5 00 60 6e 21 22 33 08 00 45 00 00 2c 00 08 00 00 ff 11 6e f8 0a 1e 1c 21 0a 1e 1c 64 dd db 07 d1 00 18 61 f7 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0d 0a 00 dm9000 tx: first packet dm9000 isr: int status 0002 dm9000 isr: int status 0001 dm9000 tx done dm9000 rx: status 0001 len 90 00 60 6e 21 22 33 08 9e 01 65 4a c5 08 00 45 00 00 48 06 c3 00 00 40 01 27 32 0a 1e 1c 64 0a 1e 1c 21 03 03 49 e7 00 00 00 00 45 00 00 2c 00 08 00 00 ff 11 6e f8 0a 1e 1c 21 0a 1e 1c 64 dd db 07 d1 00 18 61 f7 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0d 0a 00 39 74 80 9f ``` 第一包发送数据同上一样,主要来看看PC回应的数据包: ``` 00 60 6e 21 22 33 08 9e 01 65 4a c5 08 00 //以太网包头 45 00 00 48 06 c3 00 00 40 01 27 32 0a 1e 1c 64 0a 1e 1c 21 //IP首部:第10字节为0x01,ICMP报文 03 03 49 e7 00 00 00 00 //ICMP首部,类型代码为0x0303:端口不可达的差错控制报文 45 00 00 2c 00 08 00 00 ff 11 6e f8 0a 1e 1c 21 0a 1e 1c 64 dd db 07 d1 00 18 61 f7 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0d 0a 00 //这是出错报文的IP首部以及数据域 39 74 80 9f //CRC ``` 由此可知,PC返回了一个端口不可达的差错控制报文。同样,如果我们的板子UDP端口没打开的情况下,PC向下发UDP数据 Lwip也会返回这个类型的报文。 另外,你甚至可以将网线拔掉,再执行一次udp_client(),也还是会成功的(ARP缓存已有对方地址),所以,网卡发送UDP数据有没有成功, TCP/IP协议是不知道的,这需要应用层的协议自己判别。若没有应用层的协议,拔掉网线的udp包发送也会被认为是发送成功的。 如此,UDP协议,就有点类似于没有应用层协议的串口。 呀,太晚了,回家吃饭了,TCP重头戏还没有写呢,后面补上。
查看更多
3
个回答
默认排序
按发布时间排序
celticzy
2013-07-15
这家伙很懒,什么也没写!
分析的比较粗略,有兴趣的朋友可以参照协议细致的分析一下。
jeffwei
2013-07-16
这家伙很懒,什么也没写!
好经验,自己也有realtouch,可惜手里工作杂乱,又在学GTK+,没能静下心来搞realtouch,只能有空看看论坛,关注一下rtt进展
撰写答案
登录
注册新账号
关注者
0
被浏览
2.4k
关于作者
celticzy
这家伙很懒,什么也没写!
提问
14
回答
54
被采纳
0
关注TA
发私信
相关问题
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【NXP-MCXA153】 定时器驱动移植
2
GD32F450 看门狗驱动适配
3
【NXP-MCXA153】看门狗驱动移植
4
RT-Thread Studio V2.2.9 Release Note
5
CherryUSB的bootuf2配置
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
freemodbus
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
7
个答案
2
次被采纳
a1012112796
18
个答案
1
次被采纳
Ryan_CW
5
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
本月文章贡献
YZRD
3
篇文章
6
次点赞
catcatbing
3
篇文章
6
次点赞
lizimu
2
篇文章
9
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部