socket fd 长什么样子?
什么是 socket fd ?粗糙的来讲,就是网络 fd,比如我们最常见的 C/S 客户端服务端的编程模式,就是网络通信的一种方式。撇开底层和协议细节,网络通信和文件读写从接口上有本质区别吗?
其实没啥区别,不就是读过来和写过去嘛,简称 IO 。
我们先看一下 socket fd 是什么样子的?随便找了个进程
root@ubuntu:~# ll /proc/1583/fd
total 0
lrwx------ 1 root root 64 Jul 19 12:37 7 -> socket:[18892]
lrwx------ 1 root root 64 Jul 19 12:37 8 -> socket:[18893]
这里我们看到 fd 7、8 都是一个 socket fd,名字:socket:[18892]
整数句柄后面一般会跟一些信息,用于帮助我们了解这个 fd 是什么。举个例子,如果是文件 fd,那么箭头后面一般是路径名称。现在拆解一下这个名字:
-
socket :标识这是一个 socket 类型的 fd
-
[18892]
:这个是一个 inode 号,能够唯一标识本机的一条网络连接;
思考下,这个 inode 号,还能再哪里能看到呢?
在 proc 的 net 目录下,因为我这个是一个走 tcp 的服务端,所以我们看一下 /proc/net/tcp
文件。这个文件里面能看到所有的 tcp 连接的信息。
root@ubuntu:~# grep -i "18892" /proc/net/tcp
18: 00000000:1F93 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 18892 1 ffff880197fba580 100 0 0 10 0
root@ubuntu:~# grep -i "18893" /proc/net/tcp
28: 00000000:1F7C 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 18893 1 ffff880197fbad00 100 0 0 10 0
知识点又来了,/proc/net/tcp
这个文件记录了 tcp 连接的信息,这份信息是非常有用的。包含了 TCP 连接的地址(16进制显示),inode 的信息,连接的状态等等。
socket fd 是什么?
环境声明:
Linux 内核版本 4.19
为了方便,如果没特意说明协议,默认 TCP 协议;
socket
可能你还没反应过来,中文名:套接字 是不是更熟悉点。Linux 网络编程甚至可以叫做套接字编程。
有些概念你必须捋一捋 。我们思考几个小问题:
socket 跟 tcp/ip 有什么区别?
就不该把这两个东西放在一起比较讨论,就不是一个东西。tcp/ip 是网络协议栈,socket 是操作系统为了方便网络编程而设计出来的编程接口而已。
理论基础是各种网络协议,协议栈呀,啥的。但是如果你要进行网络编程,落到实处,对程序猿来讲就是 socket 编程。
对于网络的操作,由 socket 体现为 open -> read/write ->close 这样的编程模式,这个统一到文件的一种形式。
socket 的 open 就是
socket(int domain, int type, int protocol)
,和文件一样,都是获取一个句柄。
网络抽象层次
网络模型一般会对应到两种:
-
完美理论的 OSI 七层模型;
-
现实应用的 5 层模型;
对应关系如下图(取自 Unix 套接字编程)
不同层次做不同的事情,不断的封装,不断的站在巨人的肩膀上,你将能做的更多。
今天,奇伢剖析的只聚焦在套接字这一层,这是程序猿摸得到的一层,位于所有网络协议之上的一层封装,网络编程又叫套接字编程,这并不是空穴来风。
套接字,是内核对贼复杂的网络协议栈的 API 封装,使得程序猿能够用极简的姿势进行网络编程。比如写一个基于 Tcp 的 C/S 的网络程序,需要用到啥?我们大概畅想下:
-
客户端和服务端都用
socket
调用创建套接字; -
服务端用
bind
绑定监听地址,用listen
把套接字转化为监听套接字,用accept
捞取一个客户端来的连接; -
客户端用
connect
进行建连,用write/read
进行网络 IO;
程序猿用着好简单!因为内核把事扛了。
socket fd 的类型
上面我们提到了套接字,这是我们网络编程的主体,套接字由 socket()
系统调用创建,但你可知套接字其实可分为两种类型,监听套接字和普通套接字。而监听套接字是由 listen()
把 socket fd 转化而成。
1 监听套接字
对于监听套接字,不走数据流,只管理连接的建立。accept
将从全连接队列获取一个创建好的 socket( 3 次握手完成),对于监听套接字的可读事件就是全连接队列非空。对于监听套接字,我们只在乎可读事件。
2 普通套接字
普通套接字就是走数据流的,也就是网络 IO,针对普通套接字我们关注可读可写事件。在说 socket 的可读可写事件之前,我们先捋顺套接字的读写大概是什么样子吧。
套接字层是内核提供给程序员用来网络编程的,程序猿读写都是针对套接字而言,那么 write( socketfd, /* 参数 */)
和 read( socketfd, /* 参数 */)
都会发生什么呢?
-
write 数据到 socketfd,大部分情况下,数据写到 socket 的内存 buffer,就结束了,并没有发送到对端网络(异步发送);
-
read socketfd 的数据ÿ