關於/proc/進程idpid/fd ,根據fd來查找連接


當創建好epoll句柄后,它就是會占用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll后,必須調用close()關閉,否則可能導致fd被耗盡。

epoll創建的fd是:

 

lrwx------ 1 root root 64 Aug 20 11:04 3 -> anon_inode:[eventpoll]

這種類型的inode,是epoll創建的。
lrwx------ 1 root root 64 Aug 20 11:04 4 -> socket:[1126425]
 

 

 

 

一篇文章:

眾所周知,在相應進程的/proc/$pid/fd 目錄下存放了此進程所有打開的fd。當然有些可能不是本進程自己打開的,如通過fork()從父進程繼承而來的。本文着着重講述socket有關的內容。當我們在fd目錄下使用 ls -l 命令查看時,會看到諸如下面的內容: 

lrwx------ 1 root root 64 Nov 21 09:44 133 -> /dev/sda1
lrwx------ 1 root root 64 Nov 21 09:44 134 -> /dev/sdb1
lrwx------ 1 root root 64 Nov 21 09:44 136 -> /dev/sdb1
lrwx------ 1 root root 64 Nov 21 09:44 137 -> socket:[22460]
lrwx------ 1 root root 64 Nov 21 09:44 138 -> socket:[7326842]
lrwx------ 1 root root 64 Nov 21 09:44 139 -> socket:[7341066]

那么這個socket:后面的一串數字是什么呢?其實是該socket的inode號。從linux內核代碼net/socket.c 中可以看出,如下

/*
 * sockfs_dname() is called from d_path().
 */
static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
dentry->d_inode->i_ino);
}

那么,知道了某個進程打開的socket的inode號后,我們可以做什么呢?這就涉及到/proc/net/tcp(udp對應/proc/net/udp)文件了,其中也列出了相應socket的inode號通過比對此字段,我們能在/proc/net/tcp下獲得此套接口的其他信息,如對應的<本地地址:端口號,遠端地址:端口號>對,窗口大小,狀態等信息。具體字段含義詳見net/ipv4/tcp_ipv4.c 中的 tcp4_seq_show 函數。cat /proc/net/tcp 如下:

sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode 

19: 0100007F:83B8 0100007F:A57D 01 00000000:00000000 00:00000000 00000000     0        0 10879 1 f622edc0 20 4 31 3 -1                             
  20: 0100007F:0FA0 0100007F:AA06 01 00000000:00000000 00:00000000 00000000     0      0 7326842 1 f5504dc0 20 4 11 5 -1 

 

注:本文中涉及的代碼以linux 2.6.30.1為基准。

另外一篇:

 

netstat統計的tcp連接數與⁄proc⁄pid⁄fd下socket類型fd數量不一致的分析

最近,線上一個應用,發現socket數緩慢增長,並且不回收,超過警告線之后,被運維監控自動重啟了。

首先到zabbix上觀察JVM歷史記錄,發現JVM-Perm space最近兩周沒有數據,猜測是程序從JDK7切換到JDK8了。問過開發人員之后,程序已經很久沒有重啟了,最近才重新發布的。而在這期間,線上的Java運行環境已經從JDK7升級到JDK8了。

因為jdk8里沒有Perm space了,換成了Metaspace。

netstat

到線上服務器上,用netstat來統計進程的connection數量。

netstat -antp | grep pid | wc -l

 

發現比zabbix上的統計socket數量要少100多,netstat統計只有100多,而zabbix上監控數據有300多。

於是到/proc/$pid/fd下統計socket類型的fd數量:

cd /proc/$pid/fd ls -al | grep socket | wc -l

發現數據和zabbix上的數據一致。

netstat是怎么統計的

下載netstat的源代碼

http://unix.stackexchange.com/questions/21503/source-code-of-netstat

apt-get source net-tools

從netstat的代碼里,大概可以看到是讀取/proc/net/tcp里面的數據來獲取統計信息的。

java和c版的簡單netstat的實現

java版的

http://www.cs.earlham.edu/~jeremiah/LinuxSocket.java

C版的:

http://www.netmite.com/android/mydroid/system/core/toolbox/netstat.c

用starce跟蹤netstat

strace netstat -antp 

可以發現netstat把/proc 下的很多數據都讀取出來了。於是大致可以知道netstat是把/proc/pid/fd 下面的數據和/proc/net/下面的數據匯總,對照得到統計結果的。

哪些socket會沒有被netstat統計到?

又在網上找了下,發現這里有說到socket如果創建了,沒有bind或者connect,就不會被netstat統計到。

http://serverfault.com/questions/153983/sockets-found-by-lsof-but-not-by-netstat

實際上,也就是如果socket創建了,沒有被使用,那么就只會在/proc/pid/fd下面有,而不會在/proc/net/下面有相關數據。

簡單測試了下,的確是這樣:

int socket = socket(PF_INET,SOCK_STREAM,0); //不使用

 

另外,即使socket是使用過的,如果執行shutdown后,剛開始里,用netstat可以統計到socket的狀態是FIN_WAIT1。過一段時間,netstat統計不到socket的信息的,但是在/proc/pid/fd下,還是可以找到。

中間的時候,自己寫了個程序,把/proc/pid/fd 下的inode和/proc/net/下面的數據比較,發現的確有些socket的inode不會出現在/proc/net/下。

用lsof查看

用lsof查看socket inode:

觸發GC,回收socket

於是嘗試觸發GC,看下socket會不會被回收:

jmap -histo:live <pid>

 

結果,發現socket都被回收了。

再看下AbstractPlainSocketImpl的finalize方法:

    /** * Cleans up if the user forgets to close it. */ protected void finalize() throws IOException { close(); }

 

可以看到socket是會在GC時,被close掉的。 
寫個程序來測試下:

public class TestServer { public static void main(String[] args) throws IOException, InterruptedException { for(int i = 0; i < 10; ++i){ ServerSocket socket = new ServerSocket(i + 10000); System.err.println(socket); } System.in.read(); } }

 

先執行,查看/proc/pid/fd,可以發現有相關的socket fd,再觸發GC,可以發現socket被回收掉了。

其它的東東

anon_inode:[eventpoll]

ls -al /proc/pid/fd
  • 1

可以看到有像這樣的輸出:

661 -> anon_inode:[eventpoll]
  • 1

這種類型的inode,是epoll創建的。

再扯遠一點,linux下java里的selector實現是epoll結合一個pipe來實現事件通知功能的。所以在NIO程序里,會有anon_inode:[eventpoll]和pipe類型的fd。

為什么tail -f /proc/$pid/fd/1 不能讀取到stdout的數據

http://unix.stackexchange.com/questions/152773/why-cant-i-tail-f-proc-pid-fd-1

總結

原因是jdk升級之后,GC的工作方式有變化,FullGC執行的時間變長了,導致有些空閑的socket沒有被回收。

本文比較亂,記錄下一些工具和技巧。

 

根據fd來查找連接

眾所周知,在相應進程的/proc/$pid/fd 目錄下存放了此進程所有打開的fd。當然有些可能不是本進程自己打開的,如通過fork()從父進程繼承而來的。本文着着重講述socket有關的內容。當我們在fd目錄下使用 ls -l 命令查看時,會看到諸如下面的內容: 

lrwx------ 1 root root 64 Nov 21 09:44 133 -> /dev/sda1
lrwx------ 1 root root 64 Nov 21 09:44 134 -> /dev/sdb1
lrwx------ 1 root root 64 Nov 21 09:44 136 -> /dev/sdb1
lrwx------ 1 root root 64 Nov 21 09:44 137 -> socket:[22460]
lrwx------ 1 root root 64 Nov 21 09:44 138 -> socket:[7326842]
lrwx------ 1 root root 64 Nov 21 09:44 139 -> socket:[7341066]

那么這個socket:后面的一串數字是什么呢?其實是該socket的inode號。從linux內核代碼net/socket.c 中可以看出,如下

/*
 * sockfs_dname() is called from d_path().
 */
static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
dentry->d_inode->i_ino);
}

那么,知道了某個進程打開的socket的inode號后,我們可以做什么呢?這就涉及到/proc/net/tcp(udp對應/proc/net/udp)文件了,其中也列出了相應socket的inode號通過比對此字段,我們能在/proc/net/tcp下獲得此套接口的其他信息,如對應的<本地地址:端口號,遠端地址:端口號>對,窗口大小,狀態等信息。具體字段含義詳見net/ipv4/tcp_ipv4.c 中的 tcp4_seq_show 函數。cat /proc/net/tcp 如

我們想查看101 Socket文件描述符的鏈接狀態該怎么看呢?聰明的注意到后面有個數字【2305224138】,這個數字又是哪兒來的呢?看客請往下看。

在/proc/net/tcp目錄下面保存了所有TCP鏈接的狀態信息。

復制代碼
代碼如下:

[root@XXXXXXX_10_1_17_138 song_test]# cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 
0: 8A11010A:7DC8 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 764789417 1 ffff881051dfcb40 99 0 0 10 -1 
1: 8A11010A:0369 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 737748331 1 ffff88106af8f7c0 99 0 0 10 -1 
51: 8A11010A:FAF4 9C01010A:0CEA 06 00000000:00000000 03:00000938 00000000 0 0 0 2 ffff8810516c01c0 
<span style="color:#ff0000;"> 52: 8A11010A:21CD 0964010A:2227 01 00000000:00000000 00:00000000 00000000 0 0 2305224138 2 ffff8801402f55c0 23 3 30 10 -1 </span> 
53: 8A11010A:FB8A 9C01010A:0CEA 06 00000000:00000000 03:000012A8 00000000 0 0 0 2 ffff8810516c04c0 
54: 8A11010A:73E5 4511010A:0050 06 00000000:00000000 03:00000EA8 00000000 0 0 0 2 ffff88106898a880 
55: 8A11010A:89AD F300010A:1F90 08 00000000:00000001 00:00000000 00000000 0 0 2305271480 1 ffff880869b59740 23 3 0 10 -1 
187: 8A11010A:0ACB 8811010A:1F90 06 00000000:00000000 03:0000028E 00000000 0 0 0 2 ffff881050e9ccc0 
188: 8A11010A:FB6C 9C01010A:0CEA 06 00000000:00000000 03:000010CB 00000000 0 0 0 2 ffff88104fd8dd80 

 

看上數字【2305224138】沒有,就是這兒來的,到此我們可以找出鏈接的IP、PORT鏈接四元組【8A11010A:21CD 0964010A:2227】這個地方是用十六進制保存的,換算成十進制方式【10.1.17.138:8653            10.1.100.9:8743】;

去網絡連接狀態里面看一下:

復制代碼
代碼如下:

[root@XXXXXXX_10_1_17_138 song_test]# netstat -ntp 
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name 
tcp 0 0 10.1.17.138:64428 10.1.1.156:3306 TIME_WAIT - 
tcp 0 0 10.1.17.138:64244 10.1.1.156:3306 TIME_WAIT - 
<span style="color:#ff0000;">tcp 0 166 10.1.17.138:8653 10.1.100.9:8743 ESTABLISHED 25465/./index_searc </span>
tcp 0 0 10.1.17.138:64394 10.1.1.156:3306 TIME_WAIT - 
tcp 0 0 10.1.17.138:29669 10.1.17.69:80 TIME_WAIT - 
tcp 0 0 10.1.17.138:46336 10.1.17.68:80 TIME_WAIT - 
tcp 0 0 ::ffff:10.1.17.138:8080 ::ffff:10.1.17.136:27247 TIME_WAIT - 

 

回到開始的問題:101 Socket文件描述符代表的是本地【10.1.17.138:8653】到【10.1.100.9:8743】的一條TCP連接!

 

或者netstat -apn 查找對應的端口。

 

Based on your example "2045" is pid number of process and "294364529" is inode number of socket. In Linux sockets use normal file operations so this is why they have inode numbers.

Example: Let assume that I have in system socket with inode number 4654214.

Netstat:

netstat -alep | egrep -i "Inode|4654214"
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 *:9999                  *:*                     LISTEN      root       4654214     10619/nc

 

https://www.cnblogs.com/gqtcgq/p/9070332.html

 

關於/proc/$pid/fd socket:[number]

 

 

https://www.jianshu.com/p/5d82a685b5b6

/proc/net/tcp中的內容由tcp4_seq_show()函數打印,該函數中有三種打印形式,我們這里這只列出狀態是TCP_SEQ_STATE_LISTENING或TCP_SEQ_STATE_ESTABLISHED的情況,如下所示:

我們編寫網絡程序經常用到netstat -anpt 查看鏈接信息,這些信息本質都市來源於/proc/net/tcp  以下是每一行的詳解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM