探索网络协议栈和网卡之间的交互

 
交互主要分为以下几个步骤:

1 创建套接字

1)什么是套接字
套接字指的实体是通信控制信息,控制信息里面包含了通信对象的IP地址,端口号和通信操作进行状态。
linux里面执行如下命令可以看到有多少个套接字:
netstat
上面就是所有的套接字以及它所包含的信息。
创建套接字指的是在内存中开辟一个存储空间,并向这个空间内写入初始化的信息。
如下所示就是python 创建socket的代码,可以看到在进行初始化的时候,传入了
绑定地址和端口信息。这些都会存储到控制信息中。
 
import socket
sk =socket.socket()
sk.bind(("127.0.0.1",8080))
sk.listen(5)
conn,address =sk.accept()
sk.sendall(bytes("Hello world",encoding="utf-8")) 
 

2 连接服务器

 
所谓的连接就是客户端和服务器端交换控制信息。
负责保存控制信息的头部:
有些控制信息在通信的整个过程中都是需要的,这些控制信息需要保存在所发送的包的内部。这些信息被称为“头部”,不同的协议和网络层在处理包的过程中都会加上自己的头部。
为了便于区分这些头部被称为“TCP 头部”, 以太网头部和IP头部。

 

在连接和断开阶段由于没有对应的实际数据,所以传递的仅仅是网络包。
 
tcp的三次握手
 
 
 
  • tcp首先发起请求,将syn设置为1,添加tcp头部,并交给ip模块传递包。
  • 服务器接收到请求之后,找到对应的套接字,并返回消息。返回的时候syn要设置为1,ack也要设置为1,如果因为某些原因无法连接时,则将rst字段设置为1。 
  • 客户端收到之后要返回一个数据包,并将ACK设置为1,这样整个连接也就建立了。
 

3 传输数据

连接建立之后,客户端就可以调用write()函数进行数据的传输。
对于较小的数据片,协议栈会等到数据填满后打包发送,这个数据的容量就是mtu值。
如果应用程序发送的数据包较小,那么会影响发送的效率,协议栈会等到数据达到mtu值之后才会发送。
当然这个是由程序来控制的。可以选择不缓存而立马发送,但是这样会造成网络的拥挤。
 
如果数据包过大,超过了mtu值那么就需要对网络包进行拆分。分成一个个的小包发送出去。
 
这样网络包就发送出去了,但是tcp是一个安全可靠的传输协议,必须保证包能够抵达服务端。
这样就需要一定的机制来保证。
 
  • 使用ack确认网络包已经收到

 

 
根据包的平均往返时间来调整ACK号的等待时间。
 
滑动窗口机制的原理,ACK值在返回的过程中可能会造成延迟,如果延迟过高,那么
必然会造成重传,如果重传势必会造成网络更加拥挤。但是如果设置等待网络ACK 包
的时间过长也会导致网络速度变慢,因此需要为延迟设置一个合适的时间。
 
 

4 断开连接

 
5 IP与以太网的包收发操作
包结构
 
网卡是物理层设备,负责将电信号转化为数字信号。虚拟网卡尤其是linux的tap设备
是对网卡的模拟,它并不负责将电信号转化为数字信号,而是一个软件,负责数字信号
的传输。
 
TCP协议的目的是保证数据的安全和可靠传输,所以它有三次握手和三次挥手的功能。
这整个算是传输层的能力。UDP也一样,不过它不具备可靠传输的能力。
 
内核协议栈的IP模块的主要功能是对包进行封装传输。它并不关心TCP做了哪些事情。
举个例子来说,我们在邮局寄东西的时候,汽车的运输人员,他们不关心运输的东西
是什么,每一个物品都封装成了一个个的包裹,包裹上面有面单,上面包含了发送地址和寄出地址。
 
IP模块在接收到包之后会做两件事情,添加IP头部和MAC头部。
MAC头部在IP头部的前面,由于在处理的时候先处理二层的MAC头部,再
处理三层的IP头部。
 
网卡有对应的网卡驱动程序,网卡的内部结构如下图所示。它的主要功能是
将数字信号转换为电信号并传输出去。

 

参考文献:
《网络是怎样连接的》
https://juejin.cn/post/6844903510509633550#heading-6

 

posted @ 2019-03-12 16:56  周围静地出奇  阅读(870)  评论(0编辑  收藏  举报