TCP/IP相关
常用调试cmd:
ping 不解释
routert 查看路由表
arp -a 查看ARP表
各数据帧包头长度
以太网包头(MAC地址): 14Bytes
IP包头: 20Bytes+0
TCP包头: 20Bytes+0
三次握手
Client端发送SYN置1,且包含自己的Seq(初始序号)的数据包
Server端把收到的对方Seq+1放进确认序列ACK,并且将自身的Seq放进数据包,且SYN置1进行发送
Client端把收到的对方Seq+1放进确认序列ACK,发送Seq=自身Seq+1的数据包
四次挥手(由于是数据传输是全双工的)
客户端主动要求断开连接,服务器ACK后停止数据接收,但还是可以发送数据,此时是半关闭状态;
Server发送断开连接,Client ACK后就完全断开连接
MTU
数据链路层所支持的最大数据包大小,一般取1500。当数据过大时,由IP层进行分片重装,但是对于IP层分片数据,如果有一个数据片丢失,由于IP层没有冲传机制,由上层(传输层)实现,此时所有的分片数据都需要重传(UDP中就存在这样的问题)
TCP_MSS
由传输层对数据进行分片,减少重传,大小一般为MTU-20(IP包头)-20(TCP包头) = 1460
MCU的MTU
对于一些内置以太网控制器的MCU,通常使用多个DMA传输描述符完成以太网数据包的搬运,其基本传输带为帧(Frame),帧的大小就是MTU,在实际使用中最好让帧大小与IP分片缓冲pbuf+14(以太网包头)的大小相吻合。
LWIP需要占用实时系统的资源占用
任务与优先级
(1)为了优化接收机制,ethernetif_input被放入一个专门轮训等待任务中,这个任务通过OSSemPend接收以太网控制器发出的接收完成中断信号,有效数据到达时向上层传递数据
(2)当需要用到BSD socket API的的时候,lwip内核层所有操作被放置到一个独立的任务(tcpip_thread),通过send/recv调用访问邮箱,完成与应用程序的交互
(3)为了防止多任务同时调用low_level_output,底层通过一个mutex完成互斥操作,这个互斥锁占用一个任务继承优先级
消息队列
Lwip里面的邮箱其实对应着ucos中的消息队列,当需要用到BSD socket API的时候,每个accept产生的tcp连接都需要占用一个独立的消息队列
内存占用
内存缓冲池大小 PBUF_POOL_SIZE (池的数量)和 PBUF_POLL_BUFSIZE(每个池大小),对应memp_malloc
MEM_SIZE普通堆内存大小,对应mem_malloc
综上,如果lwip不需要使用操作系统,移植只需要实现底层的low_level_init、low_level_output、low_level_input,当然,需要注意ethernetif_input不要用到信号量阻塞的方式。
最后需要让不带OS的lwip跑起来,还需要在main函数主循环中周期性调用ethernetif_input提交网卡接收到的有效数据,还需要周期性调用lwip中需要用到的定时方法:tcp_tmr(TCP定时函数,周期250ms)、etharp_tmr(ARP定时函数)
多连接处理
(1)可以使用select完成对所有套接字(socket其实就是一个文件描述符)进行阻塞等待管理,当监听套接字listen_socket被访问的时候,调用accept完成连接请求,当后面产生的transfer_socket被访问时,进行send/recv处理;
(2)当accept接收到连接请求,可以创建一个新任务用于管理此连接数据交互,把这个连接包括socket、socketaddr等信息作为入参,构建一个并发服务器。