前几天看到有人发的一个面试题,问的是MySQL连贯的过程描述符的问题。
在Linux里,所有皆文件,那过程描述符,理论就是文件描述符了。
咱们还晓得Linux 内核提供了一种通过 proc文件系统,/proc 文件系统是一个虚构文件系统,通过它能够应用一种新的办法在 Linux内核空间和用户间之间进行通信。在 /proc文件系统中,咱们能够将对虚构文件的读写作为与内核中实体进行通信的一种伎俩,然而与一般文件不同的是,这些虚构文件的内容都是动态创建的。用户和应用程序能够通过proc失去零碎的信息,并能够扭转内核的某些参数。
/proc目录通常对用户来说是只读的,如果你间接在bash下想要批改一个文件是权限有余的。然而对系统来说是可写的,因而也就能够通过编程来实现增删改查。
查看socket描述符
那么,这个文件描述符就肯定是在/proc 目录了。想必那就是在相应过程的/proc/$pid/fd 目录下寄存了此过程所有关上的fd。
<code class="bash">[root@localhost fd]# pwd /proc/1723/fd [root@manager 1723]# ll fd|grep socket lrwx------ 1 root root 64 Jul 7 13:49 103 -> socket:[5722374] lrwx------ 1 root root 64 Jul 7 13:49 104 -> socket:[5057632] lrwx------ 1 root root 64 Jul 7 13:49 105 -> socket:[5722375] lrwx------ 1 root root 64 Jul 7 13:49 106 -> socket:[5057636] lrwx------ 1 root root 64 Jul 7 13:49 107 -> socket:[5983188] lrwx------ 1 root root 64 Jul 7 13:49 124 -> socket:[5983189] lrwx------ 1 root root 64 Jul 7 13:49 130 -> socket:[27456] lrwx------ 1 root root 64 Jul 7 13:49 131 -> socket:[27458] lrwx------ 1 root root 64 Jul 7 13:49 132 -> socket:[27460] lrwx------ 1 root root 64 Jul 7 13:49 51 -> socket:[23447] lrwx------ 1 root root 64 Jul 7 13:49 52 -> socket:[23448] lrwx------ 1 root root 64 Jul 7 13:49 78 -> socket:[5057630] lrwx------ 1 root root 64 Jul 7 13:49 79 -> socket:[5721339] lrwx------ 1 root root 64 Jul 7 13:49 80 -> socket:[3639663] lrwx------ 1 root root 64 Jul 7 13:49 81 -> socket:[5057631] lrwx------ 1 root root 64 Jul 7 13:49 82 -> socket:[5721340] lrwx------ 1 root root 64 Jul 7 13:49 95 -> socket:[5722372]
这个后果,和netant看到的相差无几
<code class="bash">[root@manager ~]# netstat -antp | grep 1723 | wc -l 16
当然,这和用lsof统计到的后果应该也是差不多的。之所以说差不多,而不是一样,是因为尽管netstat和lsof尽管也是读取的/proc文件系统,然而有本人的过滤和判断条件,比方这两个工具除了读取/proc/pid/fd目录,还会读取/proc/net/tcp(udp)文件。因而,如果socket创立了,没有被应用,那么就只会在/proc/pid/fd上面有,而不会在/proc/net/tcp(udp),那么netstat就统计不到了。
那么这个socket:前面的一串数字是什么呢?看起来像是端口号,有些又显著不是,其实是该socket的inode号。
那么,晓得了某个过程关上的socket的inode号后,咱们能够做什么呢?这就波及到/proc/net/tcp(udp对应/proc/net/udp)文件了,其中也列出了相应socket的inode号通过比对此字段,咱们能在/proc/net/tcp下取得此套接口的其余信息,如对应的<本地地址:端口号,远端地址:端口号>四元组,窗口大小,状态等信息。具体字段含意详见net/ipv4/tcp_ipv4.c 中的 tcp4_seq_show 函数。
<code class="bash"> [root@manager net]# cat /proc/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15528 1 ffff880426f60000 100 0 0 10 0 1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 19300 1 ffff880426f607c0 100 0 0 10 0 2: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 20170 1 ffff88042dfc8000 100 0 0 10 0 3: 00000000:21DE 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21513 1 ffff88042dfc87c0 100 0 0 10 0 4: 55F9B40A:0016 59CDB40A:2779 01 00000000:00000000 02:000936FD 00000000 0 0 6004930 2 ffff88042dfca6c0 22 6 1 10 -1 5: 55F9B40A:0016 59CDB40A:2733 01 00000030:00000000 01:00000018 00000000 0 0 5984362 4 ffff880426f645c0 25 4 31 10 -1 6: 55F9B40A:0016 59CDB40A:2778 01 00000000:00000000 02:000936FD 00000000 0 0 6004866 2 ffff88042dfcae80 24 7 1 10 -1 7: 55F9B40A:8F2E 55F9B40A:20F9 01 00000000:00000000 00:00000000 00000000 0 0 22051 1 ffff88042dfc9f00 20 4 30 10 -1 8: 55F9B40A:0016 59CDB40A:2738 01 00000000:00000000 02:000843C9 00000000 0 0 5983909 2 ffff880426f664c0 22 4 21 7 6 [root@manager net]#
这个文件怎么解读呢,咱们临时只看第一局部
8: 55F9B40A:0016 59CDB40A:2738 01 | | | | | |--> connection state(套接字状态) | | | | |------> remote TCP port number(远端端口,主机字节序) | | | |-------------> remote IPv4 address(远端IP,网络字节序) | | |--------------------> local TCP port number(本地端口,主机字节序) | |---------------------------> local IPv4 address(本地IP,网络字节序) |----------------------------------> number of entry
比方咱们看到59CDB40A:2738这个rem_address,很天然它就是TCP的四元组,十六进制转为二进制后就是
89.205.180.10:10040,留神此处IP地址应该是10.180.205.89。用lsof验证下
<code class="bash">[root@manager net]# lsof -i|grep 10040 sshd 17757 root 3u IPv4 5983909 0t0 TCP manager.bigdata:ssh->10.180.205.89:10040 (ESTABLISHED)
connection state(套接字状态),不同的数值代表不同的状态,参照如下:
TCP_ESTABLISHED:1 TCP_SYN_SENT:2 TCP_SYN_RECV:3 TCP_FIN_WAIT1:4 TCP_FIN_WAIT2:5 TCP_TIME_WAIT:6 TCP_CLOSE:7 TCP_CLOSE_WAIT:8 TCP_LAST_ACL:9 TCP_LISTEN:10 TCP_CLOSING:11
咱们看的这条数据并不是MySQL的连贯。问题来了,为什么MySQL里看到那么多fd,netstat也看到了很多,然而 /proc/net/tcp 下并没有那么多socket描述符呢。后面说过了,/proc/net/tcp(udp)能够认为是proc/pid/fd的子集,然而这也差的太离谱了。其实起因很简略,如果你在 /proc/net/tcp下找不到,试试去/proc/net/tcp6 下找找呢。
敞开指定socket连贯
如果咱们再进一步,咱们当初能够找到每个pid下的socket描述符,如果我想断掉这个描述符也就是断开这个连贯,怎么做呢?用防火墙显然不是好主见,防火墙通常是针对某个IP和固定端口的。这个时候,socket fd号就派上用场了。留神,fd和inode是两码事。
查看以后fd
<code class="bash">(base) [root@manager ~]# ll /proc/1723/fd|grep socket lrwx------ 1 root root 64 Jul 7 13:49 103 -> socket:[10232948] lrwx------ 1 root root 64 Jul 7 13:49 105 -> socket:[9490029] lrwx------ 1 root root 64 Jul 7 13:49 107 -> socket:[10232952] lrwx------ 1 root root 64 Jul 7 13:49 124 -> socket:[10232954] lrwx------ 1 root root 64 Jul 7 13:49 130 -> socket:[27456] lrwx------ 1 root root 64 Jul 7 13:49 131 -> socket:[27458] lrwx------ 1 root root 64 Jul 7 13:49 132 -> socket:[27460] lrwx------ 1 root root 64 Jul 7 13:49 51 -> socket:[23447] lrwx------ 1 root root 64 Jul 7 13:49 52 -> socket:[23448] lrwx------ 1 root root 64 Jul 7 13:49 79 -> socket:[10882498]
当初在另外一台服务器,间接用命令行mysql -h连贯本机的mysql服务,而后再查看下fd列表
<code class="bash">(base) [root@manager ~]# ll /proc/1723/fd|grep socket lrwx------ 1 root root 64 Jul 7 13:49 103 -> socket:[10232948] lrwx------ 1 root root 64 Jul 7 13:49 105 -> socket:[9490029] lrwx------ 1 root root 64 Jul 7 13:49 107 -> socket:[10232952] lrwx------ 1 root root 64 Jul 7 13:49 124 -> socket:[10232954] lrwx------ 1 root root 64 Jul 7 13:49 130 -> socket:[27456] lrwx------ 1 root root 64 Jul 7 13:49 131 -> socket:[27458] lrwx------ 1 root root 64 Jul 7 13:49 132 -> socket:[27460] lrwx------ 1 root root 64 Jul 7 13:49 51 -> socket:[23447] lrwx------ 1 root root 64 Jul 7 13:49 52 -> socket:[23448] lrwx------ 1 root root 64 Jul 7 13:49 79 -> socket:[10882498] lrwx------ 1 root root 64 Jul 7 13:49 80 -> socket:[11222776]
比照下,最上面多进去的一行就是新增的那个连贯,fd=80,socket inode=11222776。
咱们应用gdb调用syscall,敞开这个fd
<code class="bash">gdb -p 1723 call close(80) quit
而后看一下,近程mysql连贯曾经断了
— 公众号