当创建好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 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  以下是每一行的详解

关于/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. MRF能量优化

    一个外国博客,写的比较清晰 http://nghiaho.com/?page_id=1366 MRF优化牛人 重庆大学的教授 1 http://qianjiye.de/2015/09/reparame ...

  2. mysql --mysqli::multi_query 和 mysqli_multi_query

    语法: 对象化:bool mysqli::multi_query ( string $query ) 过程化:bool mysqli_multi_query ( mysqli $link , stri ...

  3. [转]Oracle dbms_random函数用法快速生成多条测试数据

    Java 随机生成中文姓名,手机号,邮编,住址:http://blog.csdn.net/xiaokui_wingfly/article/details/45913885 Java 批量随机生成身份证 ...

  4. python+selenium之自定义封装一个简单的Log类

    python+selenium之自定义封装一个简单的Log类 一. 问题分析: 我们需要封装一个简单的日志类,主要有以下内容: 1. 生成的日志文件格式是 年月日时分秒.log 2. 生成的xxx.l ...

  5. matplotlib库解析

    matplotlib 是python最著名的2D绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中.通过简单的绘图语 ...

  6. Python tushare 初步了解

    一.安装 1.Python 2.numpy 3.pandas 4.lxml 5.............. n.tushare 二.初步测试

  7. hdu1024(最大m串子序列)

    m的范围没给,很坑爹 Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ( ...

  8. Tiny4412 Android 5.0 编译系统学习笔记

    1.Android 编译系统概述 Build 系统中最主要的处理逻辑都在 Make 文件中,而其他的脚本文件只是起到一些辅助作用. 整个 Build 系统中的 Make 文件可以分为三类: ① Bui ...

  9. 五 Android Studio打包Eegret App (包名和签名,打出正式包)

    一 定义包名 如下图,在AndroidManifest.xml中的package就是包名 二 创建keystore 选择Build->Generate Signed APK 选择create n ...

  10. MAC OSX安装多个版本的JAVA(jdk jre通用)

    MAC自带的jdk1.6是苹果公司自己修改的jdk版本,被广泛应用于各种mac软件,具有不可替代性:同时,java1.7和1.8有时也需要用到.因此,在mac上安装.使用多个版本的java具有重要意义 ...