我正在编写一个实用程序来检查 /proc/net/tcp 和 tcp6 是否存在活动连接,因为它比解析 netstat 输出更快。
由于我实际上没有启用 ipv6,因此我主要使用 localhost 作为参考点。这是我的 /proc/net/tcp6 的副本
sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000000000000000000000000000:006F 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 19587 1 ffff880262630000 100 0 0 10 -1
1: 00000000000000000000000000000000:0050 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 22011 1 ffff880261c887c0 100 0 0 10 -1
2: 00000000000000000000000000000000:0016 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21958 1 ffff880261c88000 100 0 0 10 -1
3: 00000000000000000000000001000000:0277 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 28592 1 ffff88024eea0000 100 0 0 10 -1
这是匹配的 netstat -6 -pant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp6 0 0 :::111 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
tcp6 中的条目 0-3 与 ::(所有 ipv6)相对应,但条目 4 据称是 ::1 的对应条目。
这就是我感到困惑的地方...
00000000000000000000000001000000 => 0000:0000:0000:0000:0000:0000:0100:0000 => ::100:0
当我通过一些代码运行::1来生成完整的十六进制表示时,我得到:
import binascii
import socket
print binascii.hexlify(socket.inet_pton(socket.AF_INET6, '::1'))
00000000000000000000000000000001
我无法通过编程将这两个值对齐,因为它们不匹配(显然)。为什么它们不匹配?为什么内核认为 ::100:0 是 ::1?
答案1
这是由于 中的字节顺序违反直觉/proc/net/tcp6
。地址被处理为四个字,每个字由四个字节组成。在每个字中,四个字节都以相反的顺序写入。
2001:0db8 :: 0123:4567:89ab:cdef would thus come out as:
B80D 0120 00000000 6745 2301 EFCD AB89 (with spaces inserted for clarity).
这可能是由于字节序差异造成的。如今大多数 PC 都使用 IA32 或 AMD64,它们使用的字节序与 IP 的设计相反。我没有其他系统可以测试,以确定您是否可以依赖 /proc/net/tcp6 始终看起来像那样。但我验证了 IA32 和 AMD64 架构都是这种情况。
答案2
找到这个用于解析 /proc/net/tcp 的 perl 模块 http://search.cpan.org/~salva/Linux-Proc-Net-TCP-0.05/lib/Linux/Proc/Net/TCP.pm 它引用了内核文档,如下所示。
This document describes the interfaces /proc/net/tcp and
/proc/net/tcp6. Note that these interfaces are deprecated in favor
of tcp_diag.
These /proc interfaces provide information about currently active TCP
connections, and are implemented by tcp4_seq_show() in
net/ipv4/tcp_ipv4.c and tcp6_seq_show() in net/ipv6/tcp_ipv6.c,
respectively.
It will first list all listening TCP sockets, and next list all
established TCP connections. A typical entry of /proc/net/tcp would
look like this (split up into 3 parts because of the length of the
line):
46: 010310AC:9C4C 030310AC:1770 01
| | | | | |--> connection state
| | | | |------> remote TCP port number
| | | |-------------> remote IPv4 address
| | |--------------------> local TCP port number
| |---------------------------> local IPv4 address
|----------------------------------> number of entry
00000150:00000000 01:00000019 00000000
| | | | |--> number of unrecovered RTO timeouts
| | | |----------> number of jiffies until timer expires
| | |----------------> timer_active (see below)
| |----------------------> receive-queue
|-------------------------------> transmit-queue
1000 0 54165785 4 cd1e6040 25 4 27 3 -1
| | | | | | | | | |--> slow start size threshold,
| | | | | | | | | or -1 if the threshold
| | | | | | | | | is >= 0xFFFF
| | | | | | | | |----> sending congestion window
| | | | | | | |-------> (ack.quick<<1)|ack.pingpong
| | | | | | |---------> Predicted tick of soft clock
| | | | | | (delayed ACK control data)
| | | | | |------------> retransmit timeout
| | | | |------------------> location of socket in memory
| | | |-----------------------> socket reference count
| | |-----------------------------> inode
| |----------------------------------> unanswered 0-window probes
|---------------------------------------------> uid
timer_active:
0 no timer is pending
1 retransmit-timer is pending
2 another timer (e.g. delayed ack or keepalive) is pending
3 this is a socket in TIME_WAIT state. Not all fields will contain
data (or even exist)
4 zero window probe timer is pending
答案3
我正在解析 Android 上的 /proc/net/tcp 和 /tcp6、/udp6,这些是我在 Java 中进行转换的简单方法。感谢 kasperd 指导我找到这个解决方案。
/**B80D01200000000067452301EFCDAB89 -> 2001:0db8:0000:0000:0123:4567:89ab:cdef
* */
public static String toRegularHexa(String hexaIP){
StringBuilder result = new StringBuilder();
for(int i=0;i<hexaIP.length();i=i+8){
String word = hexaIP.substring(i,i+8);
for (int j = word.length() - 1; j >= 0; j = j - 2) {
result.append(word.substring(j - 1, j + 1));
result.append((j==5)?":":"");//in the middle
}
result.append(":");
}
return result.substring(0,result.length()-1).toString();
}
/**0100A8C0 -> 192.168.0.1*/
public static String hexa2decIPv4 (String hexa) {
StringBuilder result = new StringBuilder();
//reverse Little to Big
for (int i = hexa.length() - 1; i >= 0; i = i - 2) {
String wtf = hexa.substring(i - 1, i + 1);
result.append(Integer.parseInt(wtf, 16));
result.append(".");
}
//remove last ".";
return result.substring(0,result.length()-1).toString();
}
/**0000000000000000FFFF00008370E736 -> 0.0.0.0.0.0.0.0.0.0.255.255.54.231.112.131
0100A8C0 -> 192.168.0.1
*/
public static String hexa2decIP (String hexa) {
StringBuilder result = new StringBuilder();
if(hexa.length()==32){
for(int i=0;i<hexa.length();i=i+8){
result.append(hexa2decIPv4(hexa.substring(i, i + 8)));
result.append(".");
}
}else {
if(hexa.length()!=8){return "0.0.0.0";}
return hexa2decIPv4(hexa);
}
//remove last ".";
return result.substring(0,result.length()-1).toString();
}
/**Simple hexa to dec, for ports
* 01BB -> 403
* */
public static String hexa2decPort(String hexa) {
StringBuilder result = new StringBuilder();
result.append(Integer.parseInt(hexa, 16));
return result.toString();
}