一:网络请求原理
(1)收发流程
假定主机A的IP地址是192.168.1.1,主机B的IP地址是192.168.1.2,都在同一子网内,则当你在主机A上运行“Ping 192.168.1.2”后,都发生了些什么呢?
1.首先,Ping命令会构建一个固定格式的ICMP请求数据包,然后由ICMP协议将这个数据包连同地址“192.168.1.2”一起交给IP层协议
2.IP层协议将以地址“192.168.1.2”作为目的地址,本机IP地址作为源地址,加上一些其他的控制信息,构建一个IP数据包,并在一个映射表(映射表由ARP实现。ARP(Address Resolution Protocol)是地址解析协议,是一种将IP地址转化成物理地址的协议)中查找出IP地址192.168.1.2所对应的物理地址(也叫MAC地址,熟悉网卡配置的朋友不会陌生,这是数据链路层协议构建数据链路层的传输单元——帧所必需的),一并交给数据链路层。
3.数据链路层构建一个数据帧,目的地址是IP层传过来的物理地址,源地址则是本机的物理地址,还要附加上一些控制信息,依据以太网的介质访问规则,将它们传送出去。
以上就是大致的网络收发流程。
(2)网卡初始化
而上文中黑体字IP层协议又是什么时候开始处理网络数据包的呢?
这得先说下网络驱动,即网卡。
网络驱动收包大致有3种情况:
no NAPI:mac每收到一个以太网包,都会产生一个接收中断给cpu,即完全靠中断方式来收包缺点是当网络流量很大时,cpu大部分时间都耗在了处理mac的中断。
netpoll:在网络和I/O子系统尚不能完整可用时,模拟了来自指定设备的中断,即轮询收包。缺点是实时性差。
NAPI :采用中断+ 轮询的方式:mac收到一个包来后会产生接收中断,但是马上关闭。直到收够了netdev_max_backlog(一个配置的变量值)个包(默认300),或者收完mac上所有包后,才再打开接收中断通过sysctl来修改 net.core.netdev_max_backlog 或者通过proc 修改/proc/sys/net/core/netdev_max_backlog
不管采用哪种方式,中断还是轮询,linux都是在内核初始化时进行网卡初始化的,调用如下
start_kernel()
--> rest_init()
--> do_basic_setup()
--> do_initcall()
-->net_dev_init()
并在net_dev_init()中进行网络包的发送和监听的处理。
(3)网卡初始化的流程:从底到上分析
先上一张网络栈的层次结构图:(注:该图片摘自《Linux内核网络栈源代码情景分析》)
1、网络接口层
* 硬件监听物理介质,进行数据的接收,当接收的数据填满了缓冲区即“网卡初始化”中NAPI部分提到的netdev_max_backlog,硬件就会产生中断,中断产生后,系统会转向中断服务子程序。
* 在中断服务子程序中,数据会从硬件的缓冲区复制到内核的空间缓冲区,并包装成一个数据结构(sk_buff),然后调用对驱动层的接口函数netif_rx()将数据包发送给链路层。该函数的实现在net/inet/dev.c中,(在整个网络栈实现中dev.c文件的作用重大,它衔接了其下的驱动层和其上的网络层,可以称它为链路层模块的实现)
2、网络层
* 就以IP数据包为例来说明,那么从链路层向网络层传递时将调用ip_rcv函数。该函数完成本层的处理后会根据IP首部中使用的传输层协议来调用相应协议的处理函数。
UDP对应udp_rcv、TCP对应tcp_rcv、ICMP对应icmp_rcv、IGMP对应igmp_rcv(虽然这里的ICMP,IGMP一般成为网络层协议,但是实际上他们都封装在IP协议里面,作为传输层对待)
3、传输层
如果在IP数据报的首部标明的是使用TCP传输数据,则在上述函数中会调用tcp_rcv函数。该函数的大体处理流程为:
“所有使用TCP 协议的套接字对应sock 结构都被挂入tcp_prot 全局变量表示的proto 结构之sock_array 数组中,采用以本地端口号为索引的插入方式,所以当tcp_rcv 函数接收到一个数据包,在完成必要的检查和处理后,其将以TCP 协议首部中目的端口号(对于一个接收的数据包而言,其目的端口号就是本地所使用的端口号)为索引,在tcp_prot 对应sock 结构之sock_array 数组中得到正确的sock 结构队列,在辅之以其他条件遍历该队列进行对应sock 结构的查询,在得到匹配的sock 结构后,将数据包挂入该sock 结构中的缓存队列中(由sock 结构中receive_queue 字段指向),从而完成数据包的最终接收。”
4、应用层
当用户需要接收数据时,首先根据文件描述符inode得到socket结构和sock结构,然后从sock结构中指向的队列recieve_queue中读取数据包,将数据包COPY到用户空间缓冲区。数据就完整的从硬件中传输到用户空间。这样也完成了一次完整的从下到上的传输。
以上就是从ping主机的案例到网络收发的底层原理的一个讲解。可见网络收发是贯穿了整个网络协议栈的每个部分的,当网络配置错误时,从完整协议栈流程中去分析错误点是个非常好的方法。下面开始说明网络配置及常见错误。
二、网络配置命令
LINUX下的网络配置命令是ifconfig类似于WINDOWS命令行中的ipconfig。可以使用ifconfig命令来配置并查看网络接口的配置情况。
1、如:
(1) 配置eth0的IP地址, 同时激活该设备。
#ifconfig eth0 192.168.1.10 netmask 255.255.255.0 up
(2) 配置eth0别名设备eth0:1的IP地址,并添加路由。
#ifconfig eth0 192.168.1.3
#route add –host 192.168.1.3 dev eth0:1
(3) 激活设备。
#ifconfig eth0 up
(4) 禁用设备。
#ifconfig eth0 down
(5) 查看指定的网络接口的配置。
#ifconfig eth0
(6) 查看所有的网络接口配置。
#ifconfig
2、 route
可以使用route命令来配置并查看内核路由表的配置情况。
例如:
(1) 添加到主机的路由。
#route add –host 192.168.1.2 dev eth0:0
#route add –host 10.20.30.148 gw 10.20.30.40
(2) 添加到网络的路由。
#route add –net 10.20.30.40 netmask 255.255.255.248 eth0
#route add –net 10.20.30.48 netmask 255.255.255.248 gw 10.20.30.41
#route add –net 192.168.1.0/24 eth1
(3) 添加默认网关。
#route add default gw 192.168.1.1
(4) 查看内核路由表的配置。
#route
(5)删除路由。
#route del –host 192.168.1.2 dev eth0:0
#route del –host 10.20.30.148 gw 10.20.30.40
#route del –net 10.20.30.40 netmask 255.255.255.248 eth0
#route del –net 10.20.30.48 netmask 255.255.255.248 gw 10.20.30.41
#route del –net 192.168.1.0/24 eth1
#route del default gw 192.168.1.1
对于1和2两点可使用下面的语句实现:
Ifconfig eth0 172.16.19.71 netmask 255.255.255.0
Route 0.0.0.0 gw 172.16.19.254
Service network restart
3、 traceroute
可以使用traceroute命令显示数据包到达目的主机所经过的路由。
例如:
#traceroute x
4、 ping
可以使用ping 命令来测试网络的连通性。
例如:
#ping x
#ping –c 4 192.168.1.12
5、 netstat
可以使用netstat命令来显示网络状态信息。
例如:
(1) 显示网络接口状态信息。
#netstat –i
(2) 显示所有监控中的服务器的Socket和正使用Socket的程序信息。
#netstat –lpe
(3) 显示内核路由表信息。
#netstat –r
#netstat –nr
(4) 显示TCP/UDP传输协议的连接状态。
#netstat –t
#netstat –u
6、 hostname
可以使用hostname命令来更改主机名。例如;
#hostname myhost
7、 arp
可以使用arp命令来配置并查看arp缓存。例如:
(1) 查看arp缓存。
#arp
(2) 添加一个IP地址和MAC地址的对应记录。
#arp –s 192.168.33.15 00:60:08:27:CE:B2
(3) 删除一个IP地址和MAC地址的对应缓存记录。
#arp –d192.168.33.15
三.Linux常见发布型号的网络配置文件:
(1)Redhat/Centos网络配置文件地址:/etc/sysconfig/network-scripts/ifcfg-eth0
文件内容及含义:
#网卡名字
DEVICE=eth0
#mac地址
HWADDR=08:00:27:a0:87:a4
#网络连接类型
TYPE=Ethernet
#网卡设备号
UUID=ce25ae0c-572f-4b81-a5a7-f96a5387690b
#网卡是否开机启动
ONBOOT=yes
#设备eth0是否可以由Network Manager图形管理工具托管
NM_CONTROLLED=yes
#ip获取方式
BOOTPROTO=static
#ip地址
IPADDR=192.168.0.210
#网关
NETMASK=255.255.255.0
#广播地址
BROADCAST=192.168.0.255
(2)Ubuntu网络配置文件地址: /etc/network/interfaces
文件内容如下:
#ping 127.0.0.1时的请求网卡,即回环地址
auto lo
iface lo inet loopback
auto eth0
#如果是自动获取ip,添加
iface eth0 inet dhcp
#如果是手动配置ip,以下同(1)的配置
iface eth0 inet static
address xxx.xxx.xxx.xxx
netmask xxx.xxx.xxx.xxx
network xxx.xxx.xxx.xxx
boardcast xxx.xxx.xxx.xxx
gateway xxx.xxx.xxx.xxx
四、网络配置常见错误及解决
网络检查完整流程如下:
1.执行service network restart或者ping 127.0.0.1看能否成功
如果不成功就是本地网卡配置错误,根据本文第一节第二部分中的网络配置文件参数去检查
1.1 mac 是否合法
虚拟机clone后mac地址还是跟母版系统一样,这样会冲突,所以需要更新mac地址
rm -f /etc/udev/rules.d/70-persistent-net.rules
reboot
1.2 网关是否跟路由器IP一致,虚拟机要检查是否跟宿主机网关一致
1.3 子网掩码是否跟宿主机一致,保证在同一个网段
1.4 IP是否合法
1.4.1 IP段必须在2-154之间,0,1,255都是特殊点,超出255更加不合法(我有一次就设置成了192.168.1.300...)
1.4.2 IP是否跟其他主机重复
2. 检查局域网主机
2.1防火墙是否开启,导致ICMP等协议无法访问
2.2 IPSec是否开启导致无法访问
2.3 网线是否没插好,在虚拟机中即网络连接方式是否没有配好
比如选择桥接方式,虚拟机所桥接的网卡一定是宿主机在用的能联网的网卡,比如下图中一定要选择第一个
同时,选择宿主机上可用网卡之后,要设置其为允许其他计算机连接,如下图
这样才能有一个可用的上网通道。
3.Internet访问时检查DNS配置
vi /etc/resolv.conf
添加 nameserver 8.8.8.8保证域名可被解析
还不行的时候检查下是不是网费欠费了。。。
以下为常见错误
(1)Request timed out
系统可以访问到主机,但是在响应时间内没有收到响应。
(2)Destination host unreachable
系统不存在到达远程主机的合法路由。要么是本机网络环境没配置好,要么是远程主机无法访问。
2.1 当虚拟机ping不通宿主机和网关:虚拟机与宿主机及网关之间没有建立通路,可以查看虚拟机与宿主机连接方式能否连通;
2.2 当虚拟机ping仅不通网关:虚拟机与网关之间没有建立通路,如果虚拟机与宿主机的连接方式没有问题,有可能是虚拟机的网卡冲突,
请关闭其他网卡并重启网络试下
(3)虚拟机宿主机可以互相ping通,但是ping外网时出现 unknow host
首先查看是否设置DNS,其次看下是否设置网关,网关是否与宿主机一致