当创建好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数量。

  1. netstat -antp | grep pid | wc -l

发现比zabbix上的统计socket数量要少100多,netstat统计只有100多,而zabbix上监控数据有300多。

于是到/proc/$pid/fd下统计socket类型的fd数量:

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

发现数据和zabbix上的数据一致。

netstat是怎么统计的

下载netstat的源代码

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

  1. 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

  1. 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/下面有相关数据。

简单测试了下,的确是这样:

  1. 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会不会被回收:

  1. jmap -histo:live <pid>

结果,发现socket都被回收了。

再看下AbstractPlainSocketImpl的finalize方法:

  1. /**
  2. * Cleans up if the user forgets to close it.
  3. */
  4. protected void finalize() throws IOException {
  5. close();
  6. }

可以看到socket是会在GC时,被close掉的。 
写个程序来测试下:

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

先执行,查看/proc/pid/fd,可以发现有相关的socket fd,再触发GC,可以发现socket被回收掉了。

其它的东东

anon_inode:[eventpoll]

  1. ls -al /proc/pid/fd
  • 1

可以看到有像这样的输出:

  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 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:

  1. netstat -alep | egrep -i "Inode|4654214"
  2. Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
  3. 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  以下是每一行的详解

关于/proc/进程idpid/fd ,根据fd来查找连接的更多相关文章

  1. proc - 进程信息伪文件系统

    描述 /proc 是一个伪文件系统, 被用作内核数据结构的接口, 而不仅仅是解释说明 /dev/kmem. /proc里的大多数文件都是只读的, 但也可以通过写一些文件来改变内核变量. 下面对整个 / ...

  2. 如何按名称或PID查找一个进程?如何按端口号查找一个进程?如何查看一个进程的CPU和内存、文件句柄使用情况?如何查看CPU利用率高的TOP10进程清单?如何根据PID强制终止进程?

    如何按名称或PID查找一个进程?如何按端口号查找一个进程?如何查看一个进程的CPU和内存.文件句柄使用情况?如何查看CPU利用率高的TOP10进程清单? 目录 如何按名称或PID查找一个进程?如何按端 ...

  3. [转]PROC简单使用用例--VC连接ORACLE

    [转]PROC简单使用用例--VC连接ORACLE 操作系统:windows 7 数据库版本:oracle 10g VS版本:VS2010 前言:连接ORACLE的方式有很多,此处仅以PROC为例,说 ...

  4. shell脚本监控调度器/proc进程是否运行(嵌套循环)

    /proc/<pid>/schedstat $/schedstat First: , Second:time spent waiting on a runqueue,这个值与上面的se.w ...

  5. 放开Linux内核对用户进程可打开文件数和TCP连接的限制

    一. 检查linux内核uname -alsb_release -a 二. 用户进程可打开文件数限制1) vim /etc/security/limits.conf*       -      nof ...

  6. PROC简单的用例--VC连接ORACLE

    操作系统:windows 7 数据库版本号:oracle 10g VS版本号:VS2010 前言:连接ORACLE有许多方法,这里只PROC外壳,说明如何连接oracle,有事吗,希望你告诉我指出,一 ...

  7. 浅谈iptables防SYN Flood攻击和CC攻击

    ------------------------本文为自己实践所总结,概念性的东西不全,这里粗劣提下而已,网上很多,本文主要说下目前较流行的syn洪水攻击和cc攻击------------------ ...

  8. ddos cc攻击简单介绍(转)

    何为syn flood攻击: SYN Flood是一种广为人知的DoS(拒绝服务攻击)是DDoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻 ...

  9. 学习笔记:CentOS 7学习之十一:文件的重定向

    1.文件描述符定义 文件描述符:是内核为了高效管理已被而打开的文件所创建的缩影,用于指向被打开的文件,所有执行I/O操作的系统调用都通过文件描述符:文件描述符是一个简单的非负整数,用于标明每一个被进程 ...

随机推荐

  1. Hadoop2.x Yarn作业提交(客户端)

    转自:http://blog.csdn.net/lihm0_1/article/details/22186833 YARN作业提交的客户端仍然使用RunJar类,和MR1一样,可参考 http://b ...

  2. 【python】NLTK好文

    From:http://m.blog.csdn.net/blog/huyoo/12188573 nltk是一个python工具包, 用来处理和自然语言处理相关的东西. 包括分词(tokenize), ...

  3. UESTC 1511(差分约束)

    题目链接:http://acm.uestc.edu.cn/problem.php?pid=1511 思路:我们可以等到这样的5个关系式: k=1:dsit[a]-dist[b]>=0&& ...

  4. python3----requests

    import requests def get_html_text(url): try: r = requests.get(url, timeout=30) r.raise_for_status() ...

  5. MP 及OMP算法解析

    转载自http://blog.csdn.net/pi9nc/article/details/18655239 1,MP算法[盗用2] MP算法是一种贪心算法(greedy),每次迭代选取与当前样本残差 ...

  6. logback中MDC使用

    今天在项目发现别人写了很多MDC.put("taskid", "testThread/heart/main_heart");或者MDC.put("ta ...

  7. 83、android的消息处理机制(图+源码分析)——Looper,Handler,Message

    转载:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html https://my.oschina.net/u/139 ...

  8. 第一次广搜!HDU1548--A Strange Lift

    一上来看见题目就用了深搜(因为只会深搜)果断内存超限(据说时间也会超限)无奈只好开始用广搜 其实广搜的思路和深搜有很多类似的地方 不过实现的过程中用到了队列 因此有点难以理解(好吧我个人认为) 这题是 ...

  9. mysql5.6的二进制包安装

    author: headsen chen data :2018-06-08  16:21:43 1. 创建存放软件文件夹 # cd / #mkdir a 2.下载MySQL5.6二进制包 cd a w ...

  10. maven 基本框架搭建

    在平时的开发中还是在写blog时,在项目实例开始都会需要一遍一遍的介绍maven框架搭建,重复性的工作让我觉得烦恼,现在展现一下Java的核心思想“重复利用”,将这个重复性的描述提取出来一次性介绍,以 ...