手写用户态协议栈,udpipeth数据包的封装,零拷贝的实现
目录;文章不重要,总结重要有福利哦
1. udp/ip/eth数据包的封装,
2. 零拷贝的实现,
3. 柔性数组
1.什么是TCP/IP
TCP/IP是一套用于网络通信的协议集合或者系统。TCP/IP协议模型就有OSI模型分为7层。但其实一般我们所谈到的都是四层的TCP/IP协议栈。
网络接口层:主要是指一些物理层层次的接口,比如电缆等
网络层:提供了独立于硬件的逻辑寻址,实现物理地址和逻辑地址的转换。网络层协议包括IP协议(网际协议),ICMP协议(互联网控制报文协议),IGMP协议(Internet组协议管理)
传输层:为网络提供了流量控制,错误控制和确认服务。传输层有两个互不相同的传输协议:TCP(传输控制协议)、UDP(用户数据报协议)
应用层:为文件传输,网络排错和Internet操作提供具体的程序应用
2.数据包
在TCP/IP协议中数据由上至下将数据封装成包,然后再由下至上的拆包。那么数据又是怎么打包的呢?
在装包的时候,每一层都会增加一些信息用于传输,这部分信息叫做报头。当上层数据到达本层的时候,会将数据加上报头打包在一起形成新的数据包继续往下一层传递。拆包的时候就是反着来了,就像俄罗斯套娃一样,拆完最外面一层得到需要的报头,向上传递。
零拷贝实现原理
内容拷贝过程
场景:从一个文件中读出并将数据传到另一台服务器实现伪代码如下:
File.read(file, buf, len); Socket.send(socket, buf, len); // 此过程涉及4次拷贝
NIO优化
在整个过程中,过程1和4是由DMA负责(类似通道Channel),并不会消耗CPU,只有过程2和3的拷贝需要CPU参与,可以直接把内核态读取缓冲区直接拷贝到套接字相关的缓冲区,优化如下图
实现方式:FileChannel的tansferTo()方法可是实现,将数据从文件通道传输到给定的可写字节的通道,替换file.read() 方法和 socket.send()方法
//获取缓冲区
Buffer buffer=ByteBuffer.allocateDirect(1024);
//获取文件通道
FileChannel fileChannel =
FileChannel.open(Paths.get(System.getProperty("user.dir") "/assets/file.txt"), StandardOpenOption.READ);
//获取socket通道
SocketChannel socketChannel=SocketChannel.open();
//将文件通道转到socket通道
fileChannel.transferTo(buffer.position(),buffer.limit(),socketChannel);
经过上述优化后后
- 上下文切换的次数从四次减少到了两次
- 数据拷贝次数从四次减少到了三次(其中DMA copy 2次,CPU copy 1次)
零拷贝的实现
Linux内核2.4及后期版本中,针对套接字缓冲区描述符做了调整,DMA自带了收集功能,内部操作发生了改变,用户使用不变,内部操作如下图: