内核怎么帮程序建立连接的

154 阅读9分钟

承接上文网络通讯原理简介以及演示通讯过程

是内核的传输控制层完成的

程序先有连接 才会发送数据 所以该过程是阻塞的

传输控制层

该层的协议有UDP、TCP
面向连接的可靠的传输协议

三次握手让双方都确认自己的输入输出都是通的
双方要为对方在内存中开辟资源
这个资源在每台主机里面 是物理的 为对方提供服务(由谁接收 怎么统计 接收队列长了多少了 ) 这个时候才有了连接

三次握手之后 才允许 程序给传输控制层传输数据

socket

socket中文是套接字
用一个四元组ip:port+ip:port(客户端ip和端口 + 服务端ip和端口)来表示
在linux系统中用一个文件描述符来代表
一个ip可以创建65535个端口
客户端IPA和服务器IPB可以建立65535个连接

IPA可以和IPB之间建立65535个连接
IPA也可以和IPC之间建立65535个连接

netstat -natp

这是一个socket连接表
服务器A可以对服务器B最多能发送65535个连接
但不妨碍对另外一台服务器发送65535个连接
所以有了资源释放的概念即断开连接

四次分手

四次分手形象描述:

A:我要和你分手
B:哼(听到了)
B:我也想和你分手
A:好啊

如果一方没有发送过来 则另外一方就会进入等待状态

curl www.baidu.com

curl调用了内核的三次握手建立连接
把请求头发送给了对方
对方一定会有响应
它也读到了响应
curl命令最后结束退出

该请求响应的过程 包含了完整的通信过程 三次握手->中间数据传输->四次分手

抓包就抓curl请求的生命周期

抓包命令:tcpdump -nn -i port 80

-nn 表示 不显示明文和localhost等 而是该显示端口显示端口 该显示ip显示ip
-i 表示 inteface 你要抓的是哪个接口
port 抓数据包里面有80端口号 因为访问百度走的80

查看网卡接口名字:ifconfig

eth0 以太坊第一块网卡

接下来是阻塞 因为还没有去访问百度
执行 curl www.baidu.com 就抓到了数据包

192.168.150.11是我本地的ip地址
随机申请了一个端口号47449 请求百度服务器61.135.169.125:80发送了一个数据包
想建立握手 这个数据包是传输控制层发送的第一个握手的数据包 长度为0
百度给响应的包也是在传输控制层完成的 长度也是0
给百度回了一个数据包 大小依然是0 
以上是三次握手的过程
接着给百度发送了一个请求头
请求头给返回了一个ack 大小0
百度给返回一个数据包 大小为1460
给百度回了一个ack
百度又给发送了一个数据包 大小1321
把数据切成了2个包
给百度回复ack确认
2个包加起来就是百度主页所有字节
本地给百度发了一个数据包 Fin 断开连接 大小是0 本地内核给百度发送的第一个分手的数据包
百度首先返回一个ack确认的包 大小0
百度又说 其实我也想和你断开连接 大小依然是0
本地再给百度回复 其实我也是这么想的

以上就是三次握手 数据传输 四次分手的过程

数据更详细 tcpdump -nn -X -i port 80

本地给百度发送请求头

百度开始返回数据(包含响应头和响应体)

nc www.baidu.com 80

类似于telnet 可以和别人建立远程连接
但是它只完成了tcp socket的三次握手

手动发送数据 GET / HTTP/1.0

两次换行才能把整个头发送出去
抓包可以看到 本地发送了请求头给百度 
百度返回了响应头
然后四次分手

四次分手可以粘成3个包

分手和ack一块发送出去 但依然是四次分手

网络层

在网络层有IP的概念 是IP地址 一个协议规定的 比如IPV4的地址怎么去写
还有IP路由协议 还有一个route路由表
两个主机跨网通信的情况才会用到路由表

在一个IP地址中包含了在哪个网 以及它在这个网里面是多少号 是由网络号和主机位2部分组成

vi /etc/sysconfig/network-scripts/ifcfg-eth0

以太坊的0号网卡
IP地址
NETMASK掩码
网关
DNS域名解析服务器 必须要知道IP地址
人使用域名去访问 但通讯的时候必须使用IP地址
所以主机会拿你写的域名读取DNS配置去换取IP地址再封数据包

IP地址是点分字节 两点之间放了一个字节byte 一个字节是8个二进制位
8个二进制位从全0到全1的过程 可以表示的十进制数是0255

IP中
192是某种01的组合
168是某种01的组合

掩码中255是全1的组合
255.255.255.0 前面3个字节都是1 第四个字节都是0

IP地址和掩码做二进制的按位与

例如192255做二进制的按位与
即某种01的组合和全1做二进制俺位与
全11 有00
所以结果还是192

192.168.150.11255.255.255.0二进制按位与的结果是
192.168.150.0 这个就是你的网络号
11是你在这个网络号的标号

路由表:route -n

目标网络192.168.150.0是一个网络号
网关全是0 表示不需要网关
eth0接口
这条记录就是通过配置文件生成的

如果想和192.168.150.0这个局域网中的其他主机通信
直接从eth0接口发出就可以了即这台主机有一个eth0网卡直连了这个192.168.150.0网络

150.11从属于192.168.150.0这个网络 因为eth0直连了这个网络

下一跳机制

局域网A 里面有一个主机 这个主机上接了一根网线会连接到外界去
一个网络里必有一个设备 即连接到内网又连接到外网  比如自己家里的路由器
家里的电脑的下一跳就是路由器

ping百度的ip地址
数据包怎么发才能发送给百度的61.135.169.121 ?

你要发给谁 拿谁的IP地址在路由表当中和掩码做与运算
和第一个条目(255.255.255.0)做与运算得到61.135.169.0

61.135.169.0192.168.150.0不一样 这个条目就被pass掉了
然后就会来到最后一个条目
61.135.169.121这个地址和0.0.0.0做与运算 得到的结果还是0.0.0.0
和前面的目标地址一样 
代表这个条目匹配上了
然后下一跳就交给了这个条目的192.168.150.2这个网关地址(路由器)
它就会给你往后继续传递
互联网中的所有设备都会从局域网中找到它的下一跳 就不管了
互联网中的网工就维护着这些路由信息 最终能跳转到百度的服务器

路由表的意义就为了找到它的下一跳

想把数据包发送给百度的地址 数据包只能写一个IP地址 那数据包上是写百度的地址(61.135.169.121)还是下一跳的地址(192.168.150.2)

如果写下一跳的地址 那么数据包就到不了百度
如果写百度的地址 那么数据包就不知道怎么下一跳

所以就需要用到链路层了

访问本局域网

同一局域网的话 走的是第一个条目
因为这个地址192.168.150.1和255.255.255.0做位与运算得到192.168.150.0
和第一个条目的目的地址匹配上了
网关0.0.0.0表示不需要下一跳 不需要路由器 接口eth0发出去 走交换机
就转发给150.1了

链路层

  • MAC地址
硬件地址 网卡地址 这个地址是路由的

解释

路由器和你是同局域网
所以通过交换机转发出去
交换机可以看MAC地址
直接转给路由器了

百度服务器上可以有很多服务 80端口即tomcat服务;22端口是ssh服务

所以三层地址才能走到百度服务器

通过MAC地址先到网关
网关走路由表下一跳
跳到了百度服务器之后
百度看端口号 找到相应的进程
最终数据包是进程与进程之间通讯的

最外层的MAC地址就是链路层决定的
链路层也有一张表

查找MAC地址:arp -a

IP地址在路由器这个网卡上

数据包中有了MAC地址 IP地址 端口 这些就可以往外发送了

总结

应用层说我得发个数据
调内核:哥们帮我建立一个连接吧 自己阻塞
传给了传输控制层
传输控制层说:你等会啊 
自个做了一个握手的包:怎么发出去了?
叫网络层:哥们 你看我这包应该怎么走 你帮我找一下下一跳 自己阻塞
网络层一看 你发给谁
从路由表找下一跳
找到下一跳之后:下一跳的MAC地址是啥?自己阻塞
问链路层:哥们你arp表中下一跳网关的IP地址它的MAC地址 你有吗?
链路层一看有 那就开始返回 
开始封这个数据包 然后发送出去
如果链路层IP地址对应的MAC地址没有的话
所以就封不出数据包出来
所以还有一个arp请求的过程

我们都知道路由表的条目在启动的时候读取配置文件就有了
arp链路层条目什么时候有的?

这台主机会发一个数据包给150.2去请求它的MAC地址
你本来要发送别人的数据包 没有这个地址 所以要请求这个地址
你又准备了一个数据包要发出去
这个时候你还没有它的MAC地址
怎么能把数据包发给它

所以这个时候有个地址叫全f
ff:ff:ff:ff:ff:ff

如果有一个数据包是这样的一个MAC地址
从你的网卡这台主机发出去之后
会被广播给你局域网所有的人的收到
然后只有150.2会给你返回一个数据包
告诉你 它的MAC地址是什么
那么你就知道了

从arp表中删除这个条目 过一会 它还会请求回来

层与层之间都是有传递依赖关系的