美文网首页
浅谈linux中的网络

浅谈linux中的网络

作者: 小小小笑呵 | 来源:发表于2019-06-27 22:23 被阅读0次

linux网络栈和tcp/ip

简单的来说,socket就是对tcp/ip的api接口。通过socket接口,两个主机建立连接后直接通过recv()和send()即可以完成两个主机之间的通信。

但是有没有想过,在TCP/IP中,在链路层,我们需要对数据包添加帧头(MAC地址信息等),IP层,我们又要为数据包添加IP头(ip地址),在传输层,我们又需要添加端口信息等。而且其中还有一些差错校验等工作我们都没有做。但是,事实上,在每一次包传输的过程中,linux网络协议栈都完成了对这些工作。而我们只需要调用内核暴露出来的系统调用(socket)就可以了

如下图所示,网络包从网卡传递到应用层可以分为如下几个步骤:

  1. 网卡接受到数据包后,将数据包存放到包接受队列中去,并且发出硬中断信号
  2. 硬中断处理程序将数据包,存放到sk_buff缓冲区中,并且发出软中断信息
  3. 内核收到软中断后,将sk_buff中取出传递给linux网络协议栈
  4. 经过网络协议栈的一些列的处理,将数据存放到了socket缓存中
  5. 应用程序通过调用socket接口从socket缓存中取出数据
network1.png

小实验

# 一台服务端server,两个客户端c1, c2,os-centos7
# server
[root@master ~]# python
Python 2.7.5 (default, Apr  9 2019, 14:30:50) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> s = socket.socket()
>>> s.bind(("x.x.x.x", 20000))  # 绑定端口
>>> s.listen(10)  # 监听该端口
# 在服务端另外打开一个端口,输入以下命令
# netstat -tnlp | grep 20000
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python
# 发现server端开始监听20000端口,从recv-q和send-q为0可以看出此时还没有客户发起连接请求
# 注:在listen状态下recv-q表示半连接状态的个数,即客户端发送了连接请求,但服务端还没有发ack报文
# 打开一个c1客户端
>>> import socket
>>> s = socket.socket()
>>> s.connect(("x.x.x.x", 20000))
# 在c1客户端中发送连接请求
# 回到server打开另一终端,输入如下命令
[root@master ~]# netstat -atnp | grep 20000
tcp        1      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:39332    ESTABLISHED -  
# 再打开另外一个客户端c2
>>> import socket
>>> s = socket.socket()
>>> s.connect(('x.x.x.x', 20000))
# 回到server中,输入如下命令
# netstat -atnp | grep 20000
tcp        2      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:47890    ESTABLISHED -                   
tcp        0      0 x.x.x.x:20000    x.x.x.x:39332    ESTABLISHED -
# 此时发现recv-q中字段为2,表示半连接的个数,即表示客户端发送了连接请求,但还没得到服务端的ack报文。半连接状态在linux也有也显示,但看不到对应的进程(对比下面建立时的区别)

# 回到server中的python终端窗口
>>> import socket
>>> s = socket.socket()
>>> s.bind(("x.x.x.x", 20000))
>>> s.listen(10)
>>> c1, addr = s.accept()  # 从半连接队中,选择一个半连接,发送确定帧,形成连接
>>> c2, addr2 = s.accept()
# 回到server中终端窗口
[root@master ~]# netstat -atnp | grep 20000
tcp        0      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:47890    ESTABLISHED 172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:39332    ESTABLISHED 172870/python
# 发现监听状态的端口的recv-q字段变为0了,并且下方显示成功建立的连接。
# 去其中一个client发送一下数据
>>> import socket
>>> s = socket.socket()
>>> s.connect(("x.x.x.x", 20000))
>>> s.send('today is a good day')
19
# 回到master的termal
[root@master ~]# netstat -atnp | grep 20000
tcp        0      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:47890    ESTABLISHED 172870/python       
tcp       19      0 x.x.x.x:20000    x.x.x.x:39332    ESTABLISHED 172870/python 
# 注意,在establish状态时,recv-q表示的接收缓冲去中还有多少数据没有被取走,发现正好是上面输入的19个字符还没有被取走
# 回到master中python终端
>>> import socket
>>> s = socket.socket()
>>> s.bind(("x.x.x.x", 20000))
>>> s.listen(10)
>>> c1, addr = s.accept()
>>> c2, addr2 = s.accept()
>>> c1.recv(5)   # 从接受队列中取走五个字符的数据
'today'
# 回到server的终端
[root@master ~]# netstat -atnp | grep 20000
tcp        0      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:47890    ESTABLISHED 172870/python       
tcp       14      0 x.x.x.x:20000    x.x.x.x:39332    ESTABLISHED 172870/python
# 发现19变成14了,正好符合实验预期

#回到一个client终端,关闭一端的连接
>>> s = socket.socket()
>>> s.connect(("x.x.x.x", 20000))
>>> s.send('today is a good day')
19
>>> s.close()
# 回到server终端
[root@master ~]# netstat -atnp | grep 20000
tcp        0      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:47890    ESTABLISHED 172870/python       
tcp        14      0 x.x.x.x:20000    x.x.x.x:39332    CLOSE_WAIT  172870/python 
# 符合tcp的要求,关闭tcp连接时,需要双方都要关闭,此时仅客户端关闭了,也要到server端去关闭连接
# 回到server终端
>>> import socket
>>> s = socket.socket()
>>> s.bind(("x.x.x.x", 20000))
>>> s.listen(10)
>>> c1, addr = s.accept()
>>> c2, addr2 = s.accept()
>>> c1.recv(5)
'today'
>>> c1.close()
# 回到server终端
[root@master ~]# netstat -atnp | grep 20000
tcp        0      0 x.x.x.x:20000    0.0.0.0:*               LISTEN      172870/python       
tcp        0      0 x.x.x.x:20000    x.x.x.x:47890    ESTABLISHED 172870/python
# 连接完全关闭了

linux常见网络命令

  1. nslookup: 查看域名的ip地址
  2. /etc/resolv.conf: 设置DNS服务器
  3. time:查看一个命令的运行时间
  4. wrk和ab: http压力测试工具
  5. sar: 查看网络每秒的传输数据
  6. /etc/sysctl.conf: 配置linux网络协议栈参数(sysctl -p 是配置生效)
配置内容 配置描述
net.ipv4.ip_forward linux内核是否可以转发数据包
net.ipv4.tcp_max_sys_backlog tcp半连接最大数目
net.ipv4.tcp_xx 一些列和tcp相关的参数
net.ipv4.udp_xx 一些列和udp相关的参数
net.core.rmem.max 套接字接受缓冲区大小
net.core.wmem_max 套接字发送缓冲区大小
  1. iptables: 数据包转发的控制
  2. ip: 查看ip地址情况
  3. ifconfig: 查看网卡及ip地址,还有网络接受/发送包的个数和字节数

小实验

# cat /etc/resolv.conf    # 查看系统配置的DNS服务器
# Generated by NetworkManager
nameserver 202.115.32.36
nameserver 8.8.8.8 

[root@master ~]# time nslookup www.baidu.com
Server:     202.115.32.36    # DNS服务器地址
Address:    202.115.32.36#53 # DNS服务器地址及其监听的端口

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
Name:   www.a.shifen.com   # 域名
Address: 182.61.200.6  # 地址
Name:   www.a.shifen.com
Address: 182.61.200.7

real    0m0.011s   # time命令所展示的时间,实际用了0.011秒
user    0m0.005s
sys 0m0.006s
# 换一个DNS服务器
[root@master ~]# echo "nameserver 8.8.8.8" > /etc/resolv.conf && cat /etc/resolv.conf
nameserver 8.8.8.8  

[root@master ~]# time nslookup www.baidu.com
Server:     8.8.8.8
Address:    8.8.8.8#53

Non-authoritative answer:
www.baidu.com   canonical name = www.a.shifen.com.
www.a.shifen.com    canonical name = www.wshifen.com.
Name:   www.wshifen.com
Address: 103.235.46.39


real    0m0.290s   # 刚刚是0.011秒,现在是0.29秒啊,慢了好多啊!还是换回来把
user    0m0.008s
sys 0m0.007s

# echo "nameserver 202.115.32.36" > /etc/resolv.conf

相关文章

  • 浅谈linux中的网络

    linux网络栈和tcp/ip 简单的来说,socket就是对tcp/ip的api接口。通过socket接口,两个...

  • linux中的根文件系统 rootfs

    浅谈linux中的根文件系统(rootfs的原理和介绍) linux中有一个让很多初学者都不是特别清楚的概念,叫做...

  • 浅谈Linux 网络 I/O 模型

    1、介绍 Linux 的内核将所有外部设备都看做一个文件来操作(一切皆文件),对一个文件的读写操作会调用内核提供的...

  • Kubernetes网络实现

    在《Linux虚拟网络技术》这篇文章中我们已经详细介绍了Linux虚拟网络技术,在《Docker网络实现》这篇文章...

  • Linux网络管理

    参考:* Linux中的网络管理——网络配置及命令 网络配置: ifconfig命令 网络配置文件:..网卡信...

  • 静态ip配置中的问题

    一.需改Linux中的网络接口配置 设置dns 重启网络服务

  • Linux网络命令有哪些?

    Linux中网络命令有哪些?在Linux系统中,与网络有关的命令有很多,其中最为常见的就是:ping、telnet...

  • 浅谈linux中的内存管理

    1 物理内存 1.1 NUMA节点 在多个CPU(指的是物理CPU[1])通过总线来访问系统中的内存,这种方式称之...

  • 浅谈Linux中的xargs命令

    在说xargs命令之前,先说两句Linux中的管道(pipe)。 管道负责单向连接前一个程序的标准输出与后一个程序...

  • 浅谈Linux Cgroups机制

    来源:浅谈Linux Cgroups机制 - 知乎 (zhihu.com)[https://zhuanlan.zh...

网友评论

      本文标题:浅谈linux中的网络

      本文链接:https://www.haomeiwen.com/subject/wwjrcctx.html