linux一切皆文件之tcp socket描述符(三)
一、知识准备
1、在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列)
2、操作这些不同的类型就像操作文件一样,比如增删改查等
二、环境准备
组件 | 版本 |
---|---|
OS | CentOS Linux release 7.5.1804 |
三、tcp socket 文件描述符
● 当我们建立一条TCP连接时,在linux操作系统中会创建一个socket文件描述符
● 通过文件描述符就能找到socket的几本信息,比如TCP四元组(client-ip:client-port --> server-ip:server-port
)
先准备2个脚本:
server.py主要用于建立客户端的连接请求,并且接收客户端传来的数据,然后将收到的数据回传给客户端
client.py每隔1秒向服务端发送一次'hello world'
server.py
import socket
server_addr = ('127.0.0.1' , 22222)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(server_addr)
sock.listen(5)
while True:
conn, clientAddr = sock.accept()
while True:
data = conn.recv(100)
conn.sendall(data)
sock.close()
client.py
import socket
import time
server_addr = ('127.0.0.1' , 22222)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(server_addr)
while True:
message = 'hello world!'
sock.send(message)
sock.recv(100)
time.sleep(1)
sock.close()
分别启动server.py与client.py
[root@localhost ~]# python /tmp/server.py &
[1] 14199
[root@localhost ~]# python /tmp/client.py &
[2] 14202
查看server.py打开的文件描述符
[root@localhost ~]# ls -l /proc/14199/fd
total 0
lrwx------ 1 root root 64 Nov 7 07:42 0 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 7 07:42 1 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 7 07:42 2 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 7 07:42 3 -> socket:[99154]
lrwx------ 1 root root 64 Nov 7 07:42 4 -> socket:[99155]
[root@localhost ~]# lsof -n | grep -E '99154|99155'
python 14199 root 3u IPv4 99154 0t0 TCP 127.0.0.1:22222 (LISTEN)
python 14199 root 4u IPv4 99155 0t0 TCP 127.0.0.1:22222->127.0.0.1:56946 (ESTABLISHED)
我们主要关注ESTABLISHED
状态的socket描述符,也就是4 -> socket:[99155]
[root@localhost fd]# more /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
...
4: 0100007F:56CE 0100007F:DE72 01 00000000:00000000 00:00000000 00000000 0 0 99155 1 ffff90d8bb0145c0 20 4 31 10 -1
进程打开了tcp socket 描述符4 -> socket:[99155]
,socket描述符指向内存中的socket结构体,该结构体详细描述了这个socket的详细信息
最重要的是TCP四元组(local_ip:local_port --> remote_ip:remote_port
),拆分转换成10进制
0100007F:56CE
[root@localhost ~]# ((d=0x01))
[root@localhost ~]# ((c=0x00))
[root@localhost ~]# ((b=0x00))
[root@localhost ~]# ((a=0x7F))
[root@localhost ~]# ((e=0x56CE))
[root@localhost ~]# echo "$a.$b.$c.$d:$e"
127.0.0.1:22222
0100007F:DE72
[root@localhost ~]# ((d=0x01))
[root@localhost ~]# ((c=0x00))
[root@localhost ~]# ((b=0x00))
[root@localhost ~]# ((a=0x7F))
[root@localhost ~]# ((e=0xDE72))
[root@localhost ~]# echo "$a.$b.$c.$d:$e"
127.0.0.1:56946
在/proc/net/tcp包含了tcp连接的重要状态信息:
00000000:00000000 : 发送队列与接收队列 (正数第四个字段)
-1 : 慢启动门限 (倒数第一个字段)
10 : 拥塞窗口 (倒数第二个字段)
这里面还有很多描述:比如慢启动门限、传输队列以及接收队列、窗口探查等TCP相关的重要参数都可以查询到,具体的大家可以去看下《TCP/IP详解卷》
client.py也存在同样的行为:
[root@localhost ~]# ls -l /proc/14202/fd
total 0
lrwx------ 1 root root 64 Nov 19 04:43 0 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 19 04:43 1 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 19 04:43 2 -> /dev/pts/0
lrwx------ 1 root root 64 Nov 19 04:43 3 -> socket:[28728]
[root@localhost ~]# lsof -n | grep 28728
python 14202 root 3u IPv4 28728 0t0 TCP 127.0.0.1:56946->127.0.0.1:22222 (ESTABLISHED)
[root@localhost fd]# more /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
...
3: 0100007F:C31A 0100007F:DE72 01 00000000:00000000 00:00000000 00000000 0 0 28728 3 ffff8a74ba1a0f80 20 4 30 10 -1
0100007F:56CE
[root@localhost ~]# ((d=0x01))
[root@localhost ~]# ((c=0x00))
[root@localhost ~]# ((b=0x00))
[root@localhost ~]# ((a=0x7F))
[root@localhost ~]# ((e=0x56CE))
[root@localhost ~]# echo "$a.$b.$c.$d:$e"
127.0.0.1:22222
0100007F:DE72
[root@localhost ~]# ((d=0x01))
[root@localhost ~]# ((c=0x00))
[root@localhost ~]# ((b=0x00))
[root@localhost ~]# ((a=0x7F))
[root@localhost ~]# ((e=0xDE72))
[root@localhost ~]# echo "$a.$b.$c.$d:$e"
127.0.0.1:56946
总结一下:
● server.py与client.py各自打开tcp socket 描述符,该描述符指向内存中的socket结构体
● socket结构体描述了关于TCP的所有信息,其中通过TCP 4元组找到对端的通信节点
● socket将用户数据以及自身结构数据封装完成之后会交给底层的TCP协议,然后是IP协议、链路层信息,最后通过物理链路到达对端
● 对端也会依次解包,直至将发送端数据写入到指定的内存当中,最终由应用程序读取(本文中的server.py或client.py)
client.py server.py
+---------------+ +---------------+
|pid:14202 | |pid:14199 |
| +-----+ | | +-----+ |
| |fd:3 | | | |fd:4 | |
| +-----+ | | +-----+ |
+---------------+ +---------------+
| |
user space | |
+---------------------------------------------------------------------+
kernel space | |
| |
v v
+------+-------+ +------+-------+
|socket:[28728]| |socket:[99155]|
+------+-------+ +------+-------+
| |
| |
v v
+----+----+ +----+----+
| socket | | socket |
+----+----+ +----+----+
| |
| |
v v
++---------------------------------+-
| tcp |
+------------------------------------
四、小结
● TCP连接中最重要的是TCP四元组,而进程打开TCP socket描述符可以找到四元组信息,从而确定双方的IP和port
● 通过socket文件描述符可以找到内存中的socket结构体,获取到TCP连接的详细信息,包括必备四元组、文件的inode、时间、出队入队状态等等
● 1个进程可以创建多个TCP连接,也就是创建多个socket文件描述符,这由该进程能够打开的文件数量限制(ulimit -n
)
五、参考资料
http://www.cs.colostate.edu/~gersch/cs457/CS457_tutorial2.pdf
https://gist.github.com/jkstill/5095725
至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...
linux一切皆文件之tcp socket描述符(三)的更多相关文章
- linux一切皆文件之Unix domain socket描述符(二)
一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列) 2.操作这些不同的类型就像操作文件一样,比如增删改查等 3.主要用于 ...
- linux一切皆文件之文件描述符(一)
一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件.如:普通文件.目录.字符设备.块设备.套接字等 2.当一个文件被进程打开,就会创建一个文件描述符.这时候,文件的路径就 ...
- linux一切皆文件之文件描述符
一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件.如:普通文件.目录.字符设备.块设备.套接字等2.当一个文件被进程打开,就会创建一个文件描述符.这时候,文件的路径就成 ...
- linux一切皆文件之tty字符设备(深入理解sshd创建pty的过程) (五)
一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列) 2.操作这些不同的类型就像操作文件一样,比如增删改查等 3.块设备支 ...
- linux一切皆文件之块设备文件(四)
一.知识准备 1.在linux中,一切皆为文件,所有不同种类的类型都被抽象成文件(比如:块设备,socket套接字,pipe队列) 2.操作这些不同的类型就像操作文件一样,比如增删改查等 3.块设备是 ...
- LINUX一切皆文件
只要用过linux的筒子,或者保守点说接触到一些linux思想的同志肯定听说过这样一句话,在linux下,“一切皆是文件”! 不错,今天walfred将在快速上手linux设备驱动这一块,谈谈linu ...
- 【读书笔记】socket描述符选项[SOL_SOCKET]
#include <sys/socket.h> int setsockopt( int socket, int level, int option_name, ...
- 绑定socket描述符到一个网络设备
网络编程中有时明明用eth0的地址来bind一个udp套接口, 可是发出去的包却是从eht1走的, 在网上找到这么一段话解释该问题: 在多 IP/网卡主机上,UDP ...
- Linux下的文件与目录操作 BY 四喜三顺
文件操作权限: chmod 三个八进制数字 文件名 其中:三个八进制数字,第一个代表本用户的权限,第二个代表同组的权限,第三个代表其他用户的权限4代表可读2代表可写1代表可执行例如:chmod 7 ...
随机推荐
- python基础学习19----socket网络编程
网络通信三要素 ip地址:InetAddress 网络中设备的标识,不易记忆,可用主机名(计算机的标识号) 端口号:用于标识进程的逻辑地址,不同进程的标识(正在运行的软件的标识号) 传输协议:通讯的规 ...
- spring-bean 版本的问题(报错:org.xml.sax.SAXParseException; lineNumber: 14; columnNumber: 75;)
当XML中配置的xsd是4.0,而引用的包是4以下的spring-bean.jar时,当服务器能连网时没问题,不能连网时,就报以下类似错误: org.xml.sax.SAXParseException ...
- .NET Core 获取配置文件appsettings.json 方法
using Abp.Extensions; using Microsoft.Extensions.Configuration; using System; using System.Collectio ...
- Linux nmap命令详解
nmap,也就是Network Mapper,是Linux下的网络扫描和嗅探工具包. nmap是在网络安全渗透测试中经常会用到的强大的扫描器.功能之强大,不言而喻.下面介绍一下它的几种扫描命令.具体的 ...
- Qt: QSqlRecord字段值为null时注意事项
QSqlRecord在对应字段值为null时,QSqlRecord::value返回的QVariant是有效但为null(相当于使用QVariant(Type type)构造的),所以此时做对应类型的 ...
- Linux运维之--zabbix使用(实时更新)
之前安装的是zabbix3.x版本,今天尝试安装zabbix4.2版本,并做个总结.建议生产环境还是使用3.4版本比较好,因为4.2版本上可能语法又增加了一些,所以建议使用熟练的版本 1.首先是安装z ...
- css常见效果
1.ul li横排 /* ul li以横排显示 */ /* 所有class为menu的div中的ul样式 */ div.menu ul { list-style:none; /* 去掉ul前面的符号 ...
- redis 持久化与备份策略
持久化(persistence) 本文是 Redis 持久化文档 的中文翻译. 这篇文章提供了 Redis 持久化的技术性描述,推荐所有 Redis 用户阅读. 要更广泛地了解 Redis 持久化,以 ...
- ATP学姐的模拟赛
ATPの水题大赛 声明:不是我觉得这题水,这就是本场模拟赛的名称. T1:求所有的$n$位数中有几个数满足:每一位要么是$A$要么是$B$,并且这个$n$位数的每一位加起来是$A$或$B$的倍数. $ ...
- 服务发现系统etcd之安装和使用
一.概述 etcd是一个高可用的键值存储系统,主要用于共享配置和服务发现.etcd是由CoreOS开发并维护的,灵感来自于 ZooKeeper 和 Doozer,它使用Go语言编写,并通过Raft一致 ...