socket 文件 linux,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)

五、参考资料

至此,本文结束

在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值