开发人员想要创建一个 TCP 性能监控工具,并希望从 TCP 信息中提取 tcpi_rtt 值。对于进程内的套接字,可以使用 Python 中的 getsockopt
函数来获取。但是,对于进程外的套接字,使用 os.open
函数打开套接字文件描述符时,会遇到 OSError: [Errno 6]
的错误。
2、解决方案
为了解决这个问题,有多种方法可以获取其他进程的 TCP 信息。
方法一:使用 bpf
工具
可以使用 bpf
工具来获取其他进程的 TCP 信息。
import bpf
bpf_prog = """
int kprobe__sock_read(struct sock *sk)
{
u32 pid = bpf_get_current_pid_tgid();
struct tcp_sock *tp = bpf_tcp_sock(sk);
bpf_printk("Process %d (tgid %d) read from TCP socket %d (state %d)\n",
pid, pid >> 32, sock_inet_sport(sk), tp->state);
return 0;
}
"""
b = bpf.BPF(text=bpf_prog)
b.attach_kprobe(event="sock_read", fn_name="kprobe__sock_read")
方法二:使用 ss
命令和 netstat
工具
可以使用 ss
命令和 netstat
工具来获取其他进程的 TCP 信息。
import subprocess
def get_tcp_info_for_process(pid):
# 通过 `ss` 命令来获取进程的 TCP 连接信息
output = subprocess.check_output(["ss", "-n", "-p", str(pid)])
# 解析 `ss` 命令的输出结果
connections = []
for line in output.decode("utf-8").splitlines():
# 分割每一行的信息
fields = line.split()
# 获取 TCP 连接的源端口、目标端口、状态等信息
local_port = fields[4].split(":")[1]
remote_port = fields[5].split(":")[1]
state = fields[2]
# 将信息存储到字典中
connection = {
"local_port": local_port,
"remote_port": remote_port,
"state": state
}
# 添加到连接列表
connections.append(connection)
return connections
def get_tcp_info_for_all_processes():
# 获取所有进程的 TCP 连接信息
output = subprocess.check_output(["netstat", "-tnp"])
# 解析 `netstat` 命令的输出结果
connections = []
for line in output.decode("utf-8").splitlines():
# 分割每一行的信息
fields = line.split()
# 获取 TCP 连接的源端口、目标端口、状态、进程 ID 等信息
local_port = fields[3]
remote_port = fields[4]
state = fields[6]
pid = fields[7].split("/")[0]
# 将信息存储到字典中
connection = {
"local_port": local_port,
"remote_port": remote_port,
"state": state,
"pid": pid
}
# 添加到连接列表
connections.append(connection)
return connections
方法三:使用 tcpdump
工具
可以使用 tcpdump
工具来获取其他进程的 TCP 信息。
import subprocess
def get_tcp_info_for_process(pid):
# 通过 `tcpdump` 命令来抓取进程的 TCP 流量
output = subprocess.check_output(["tcpdump", "-n", "-i", "lo", "host", str(pid)])
# 解析 `tcpdump` 命令的输出结果
connections = []
for line in output.decode("utf-8").splitlines():
# 分割每一行的信息
fields = line.split()
# 获取 TCP 连接的源端口、目标端口、状态等信息
src_addr = fields[2].split(":")[0]
src_port = fields[2].split(":")[1]
dst_addr = fields[4].split(":")[0]
dst_port = fields[4].split(":")[1]
state = fields[6]
# 将信息存储到字典中
connection = {
"src_addr": src_addr,
"src_port": src_port,
"dst_addr": dst_addr,
"dst_port": dst_port,
"state": state
}
# 添加到连接列表
connections.append(connection)
return connections
def get_tcp_info_for_all_processes():
# 获取所有进程的 TCP 流量
output = subprocess.check_output(["tcpdump", "-n", "-i", "lo"])
# 解析 `tcpdump` 命令的输出结果
connections = []
for line in output.decode("utf-8").splitlines():
# 分割每一行的信息
fields = line.split()
# 获取 TCP 连接的源端口、目标端口、状态、进程 ID 等信息
src_addr = fields[2].split(":")[0]
src_port = fields[2].split(":")[1]
dst_addr = fields[4].split(":")[0]
dst_port = fields[4].split(":")[1]
state = fields[6]
pid = fields[7].split("/")[0]
# 将信息存储到字典中
connection = {
"src_addr": src_addr,
"src_port": src_port,
"dst_addr": dst_addr,
"dst_port": dst_port,
"state": state,
"pid": pid
}
# 添加到连接列表
connections.append(connection)
return connections
通过以上三种方法,可以获取其他进程的 TCP 信息,以方便开发 TCP 性能监控工具。