Linux下C/C++实现类似netstat命令(列出TCP和UDP连接)

news2024/10/7 3:17:34

网络连接一般包括最基本的五元组信息(源地址、目标地址、源端口、目标端口、协议号)再加上所属进程信息pid, exe, cmdline等。其中这两项数据大多可直接读取linux /proc目录下的网络状态连接文件/proc/net/tcp、/proc/net/udp), 进程状态目录(/proc/pid/xx)。

Linux 下的/proc/net子目录

在这里插入图片描述
net该子目录包括多个 ASCII 格式的网络伪文件, 描述了网络 层的部分情况. 可以用 cat 来察看这些文件, 但标准的 netstat(8) 命令组更清晰地给出了这些文件的信息.

我们讲解下面的文件网络状态文件/proc/net/tcp、/proc/net/tcp6、/proc/net/udp、/proc/net/udp6

proc_net_tcp.txt介绍了/proc/net/tcp和/proc/net/tcp6接口。这些接口展示了tcp的连接信息。

它将首先列出所有侦听TCP套接字,然后列出所有已建立的TCP连接。/proc/net/tcp、/proc/net/tcp6的典型条目如下(由于行的长度,分为三部分):

在这里插入图片描述
tcp该文件保存了 TCP 套接字表, 大部分信息除用于调试以外没有什么用.

"sl" 指出了套接字的内核散列槽号;
"local address" 包括本地地址和端口号;
"remote address" 包括远地地址和端口号(如果有连接的话); 
   'St' 是套接字的内 部状态; 
   'tx_queue''rx_queue' 是内核存储器使用意义上 的输入输出数据队列;
    "tr", "tm->when""rexmits" 保存了内核套接字声明的内部信息, 只用于调试; 
    uid 是套接字创建者的有效 uid.
   46: 010310AC:9C4C 030310AC:1770 01 
   |      |      |      |      |   |--> connection state(套接字状态)
   |      |      |      |      |------> remote TCP port number(远端端口,主机字节序)
   |      |      |      |-------------> remote IPv4 address(远端IP,网络字节序)
   |      |      |--------------------> local TCP port number(本地端口,主机字节序)
   |      |---------------------------> local IPv4 address(本地IP,网络字节序)
   |----------------------------------> number of entry

 00000150:00000000 01:00000019 00000000  
     |        |     |     |       |--> number of unrecovered RTO timeouts(超时重传次数)
     |        |     |     |----------> number of jiffies until timer expires(超时时间,单位是jiffies)
     |        |     |----------------> timer_active (定时器类型,see below)
     |        |----------------------> receive-queue(根据状态不同有不同表示,see below)
     |-------------------------------> transmit-queue(发送队列中数据长度)

   1000        0 54165785 4 cd1e6040 25 4 27 3 -1
    |          |    |     |    |     |  | |  | |--> slow start size threshold, 
	                                                or -1 if the threshold is >=0xFFFF 
    |          |    |     |    |     |  | |  |     (如果慢启动阈值大于等于0xFFFF则显示-1,否则表示慢启动阈值)
    |          |    |     |    |     |  | |  |      
    |          |    |     |    |     |  | |  |----> sending congestion window(当前拥塞窗口大小)
    |          |    |     |    |     |  | |-------> (ack.quick<<1)|ack.pingpong
	                                               (快速确认数和是否启用的标志位的或运算结果)    
    |          |    |     |    |     |  |---------> Predicted tick of soft clock (delayed ACK control data)
	                                               (用来计算延时确认的估值)
    |          |    |     |    |     |             
    |          |    |     |    |     |------------> retransmit timeout()(RTO,单位是clock_t|          |    |     |    |------------------> location of socket in memory(socket实例的地址)
    |          |    |     |-----------------------> socket reference count(socket结构体的引用数)
    |          |    |-----------------------------> inode(套接字对应的inode)
    |          |----------------------------------> unanswered 0-window probes(see below)
    |---------------------------------------------> uid(用户id)

connection state(套接字状态),不同的数值代表不同的状态,参照如下:

01: “ESTABLISHED”,02: “SYN_SENT”,03: “SYN_RECV”,04: “FIN_WAIT1″,05: “FIN_WAIT2″,06: “TIME_WAIT”,07: “CLOSE”,08: “CLOSE_WAIT”,09: “LAST_ACK”,0A”: “LISTEN”,0B”: “CLOSING” 

receive-queue:当状态是ESTABLISHED,表示接收队列中数据长度;状态是LISTEN,表示已经完成连接队列的长度。

timer_active:

 0  no timer is pending  //没有启动定时器
 1  retransmit-timer is pending  //重传定时器
 2  another timer (e.g. delayed ack or keepalive) is pending  //连接定时器、FIN_WAIT_2定时器或TCP保活定时器
 3  this is a socket in TIME_WAIT state. Not all fields will contain data (or even exist)  //TIME_WAIT定时器
 4  zero window probe timer is pending  //持续定时器

unanswered 0-window probes:持续定时器或保活定时器周期性发送出去但未被确认的TCP段数目,在收到ACK之后清零


udp该文件保存了 UDP 套接字表, 大部分信息除用于调试以外没有什么用。

"sl" 指出了套接字的内核散列槽号; 
"local address" 包括本地地址和端口号; 
"remote address" 包括远地地址和端口号(如果有连接的话); 
"St" 是套接字的内 部状态; 
"tx_queue""rx_queue" 是内核存储器使用意义上 的输入输出数据队列;
UDP 没有使用 "tr","tm-&gt;when""rexmits";
uid 是套接字创建者的有效 uid

Linux下实现类似netstat命令

...
void checkProc(struct ProcNet *Net, int len, int flag, const char protocol[])
{
	char path[1000], buf2[256], link[64], tmp[10], inode[15], p_name[512];
	int ret;
	//ino_t inode;
	ssize_t link_size;
	//printf("flag: %d\n", flag);

	if ((proc = opendir("/proc")) == NULL)
	{
		perror("Cannot open /proc directory\n");
		exit(1);
	}

	while ((procent = readdir(proc)) != NULL)
	{
		if (!isdigit(*(procent->d_name)))
			continue;
		sprintf(buf2, "/proc/%s/fd", procent->d_name);
		//printf("%s\n", buf2);

		if ((fd = opendir(buf2)) == NULL)
			continue;
		while((fdent = readdir(fd)) != NULL)
		{
			struct stat st;

			sprintf(buf2, "/proc/%s/fd/%s", procent->d_name, fdent->d_name);
			if (stat(buf2, &st) < 0)
				continue;
			if (!S_ISSOCK(st.st_mode))
				continue;
			ret = checkInode(Net, st.st_ino, len);
			if (ret >= 0)
			{
				if (flag)
				{
					if (read_program_name_args_filter(procent))
					{
						display_at(Net, ret, protocol);
						printf("%s/", procent->d_name);
						read_program_name_args(procent);
					}
				}
				else
				{	
					display_at(Net, ret, protocol);
					printf("%s/", procent->d_name);
					read_program_name_args(procent);
				//printf("%s", p_name);
				}
			}
		}
		closedir(fd);
	}	
	//printf("here\n");
	closedir(proc);
}
...
static const char *state2str(unsigned state)
{
    switch(state){
    case 0x1: return "ESTABLISHED";
    case 0x2: return "SYN_SENT";
    case 0x3: return "SYN_RECV";
    case 0x4: return "FIN_WAIT1";
    case 0x5: return "FIN_WAIT2";
    case 0x6: return "TIME_WAIT";
    case 0x7: return "CLOSE";
    case 0x8: return "CLOSE_WAIT";
    case 0x9: return "LAST_ACK";
    case 0xA: return "LISTEN";
    case 0xB: return "CLOSING";
    default: return "UNKNOWN";
    }
}



int main(int argc, char *argv[])
{
...

	static struct option long_options[] = {
		{"tcp", optional_argument, 0, 't'},
		{"udp", optional_argument, 0, 'u'},
		{0,		0,			 0,	 0}
	};
	int long_index = 0;

	while((opt = getopt_long(argc, argv, ":tu", long_options, &long_index)) != -1)
	{
		//printf("%d,", long_index);
		switch(opt)
		{
			case 't':
				tcp = 1;
				udp = 0;
				if (opt_flag)
					udp = 1;
				++opt_flag;
				
				break;
			case 'u':
				udp = 1;
				tcp = 0;
				if (opt_flag)
					tcp = 1;
				++opt_flag;
				break;
			case '?':
				printf("Usage: ./my_netstat [-t|--tcp][-u|--udp] [filter-string | \"regular expression\"]\n");
				exit(1);
		}
	}

	if (optind < argc)
	{
		filter_string = argv[optind];
		filter = 1;
		//printf("filter string: %s ", filter_string);
		/* Compile regular expression */
        reti = regcomp(&regex, filter_string, 0);
        if( reti ){ fprintf(stderr, "Could not compile regex\n"); exit(1); }
	}
	//printf("\ntcp: %d, udp: %d\n", tcp, udp);

	int num_tcp, num_udp;
	
	if (tcp)
	{
		printf("\n\nList of TCP connections::: \n");
		printf("Proto \tLocal Address \t\t\tForeign Address \t\tstate \t\tPID/Program name and arguments \n");
		printf("---------------------------------------------------------------------------------------------------------------\n");
		num_tcp = checkTCP();
		num_tcp++;

		//display(TCPdata, num_tcp);
		//printf("\n Number of TCP: %d\n", num_tcp);
		checkProc(TCPdata, num_tcp, filter, "tcp");
	}

	if (udp)
	{
		printf("\nList of UDP connections::: \n");
		printf("Proto \tLocal Address \t\t\tForeign Address \t\tstate \t\tPID/Program name and arguments \n");
		printf("---------------------------------------------------------------------------------------------------------------\n");
		num_udp = checkUDP();
		num_udp++;
		checkProc(UDPdata, num_udp, filter, "udp");
	}

	return 0;
}

If you need the complete source code of my_netstat, please add WeChat number (c17865354792)​

编译运行:


在这里插入图片描述
./my_netstat -u
./my_netstat -t

总结

这是一个简单的netstat(类似netstat)。该程序列出了所有现有的TCP和UDP连接。对于每个已标识的连接(套接字描述符),查找相应的进程名称及其创建连接的命令行(套接字描述符)。

Welcome to follow WeChat official account【程序猿编码
参考:https://www.kernel.org/doc/html/v5.8/networking/proc_net_tcp.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/80766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基于JSP的报刊订阅管理系统

随着人类的发展&#xff0c;人们对信息的获取方式也越来越多&#xff0c;虽然很多时候人们习惯了通过手机来获取各类信息&#xff0c;但是手机也逐渐的成为了危害人类健康的杀手之一&#xff0c;为了能够让大家回归到健康的生活中来&#xff0c;我开发了本系统&#xff0c;旨在…

基于jsp+mysql+ssm医药进销存管理系统-计算机毕业设计

项目介绍 为了减少传统医药进销存管理的繁杂的工作量&#xff0c;提高医药进销存管理的效率而设计开发了此系统。本系统综合各方面的需求决定采用B/S架构&#xff0c;并利用clipse搭建java开发平台。从而共同完成整个医药的设计开发。系统实现的功能主要包括&#xff1a;用户在…

java 通过InetAddress获取ip 计算机名称操作

本文属于java网络编程部分 需要你的网络编程三要素 有所了解 如果您尚未了解 可以先查看我的文章 java网络编程三要素 而 为了更好的获取和使用IP地址 java提供了InetAddress类 来到文档 首先 他在 java的net包下 所以 想用它 是需要导包的 根据文档叙述 InetAddress就是一个…

python数据分析及可视化(十七)聚宽(双均线分析、因子选股策略、多因子选股策略、均值回归理论、布林带策略、PEG策略、权重收益策略)

聚宽 聚宽是一个做金融量化的网站&#xff0c;https://www.joinquant.com&#xff0c;登录注册&#xff0c;如果你写的文章、策略被别人采纳&#xff0c;增加积分&#xff0c;积分用于免费的回测时长。在我的策略&#xff0c;进入策略列表&#xff0c;里面有做好的策略模板可以…

Web前端105天-day40-GIT

git--版本控制系统(VCS) 目录 前言 一、版本控制系统(VCS) 二、Git中的常用概念 三、Git中的常用命令 四、分支 五、远程仓库(代码托管平台) 总结 前言 day40学习开始 一、版本控制系统(VCS) 用于项目中文件的存储、共享、历史回退、合并、代码追踪文件历史常用版本控制…

acwing基础课——spfa

由数据范围反推算法复杂度以及算法内容 - AcWing 常用代码模板3——搜索与图论 - AcWing 基本思想&#xff1a; 一般单源最短路我们都可以用spfa算法来做&#xff0c;如果过不了再尝试其他算法。 spfa算法就是在bellman-ford算法的基础上就行优化&#xff0c;bellman-算法是每…

微信小程序|小程序事件

首先,我们在index.wxml中与index.js中添加如下代码: <button bindtap="alert">bindtap</button>Page({data: {},alert: function (event) {wx.showToast({title: 触发成功, // 标题icon: success, // 图标类型,默认successduration: 1500 // 提示窗停…

贪吃蛇复现-CoCube

需要完成下面所提及博文中里面所有前序案例&#xff1a; 从开环到闭环的旅程-CoCube 在完成如上代码之后&#xff0c;添加一个彩蛋&#xff0c;贪吃蛇的案例。 蓝桥ROS之半自动贪吃龟turtlesim版 基本上就是上述代码复现一下&#xff0c;完全没有难度的。 贪吃蛇复现-CoCubep…

程序员最关心的问题,我都帮你们问AI了

前言 最近几天互联网刮起了一阵ChatGPT风&#xff0c;起因是OpenAI发布了一个全新的聊天机器人模型—— ChatGPT&#xff0c;可以像人类交谈般回答大部分问题甚至还能直接帮你写代码。 我们先来试试让它帮我们写个代码&#xff1a; 有一丝丝的恐惧&#xff0c;害怕过两年就会失…

redis—主从,哨兵,集群

redis常见的使用方式 Redis的几种常见使用方式包括: Redis单副本;Redis多副本(主从) ;Redis Sentinel (哨兵) ;Redis Cluster;Redis自研。 使用场景: 如果数据量很少&#xff0c;主要是承载高并发高性能的场景&#xff0c;比如缓存一般就几个G的话&#xff0c; 单机足够了。…

Qt扫盲-QPushButton 理论总结

QPushButton 理论总结一、简述二、常用要点1. 快捷键相关2. 信号相关3. 默认按钮3. 推荐使用4. 重复功能5. 菜单功能一、简述 PushButton 按钮或CommandButton 按钮应该是图形用户界面中最常用的小部件。按下&#xff08;单击&#xff09;一个按钮就可以命令计算机执行某些操作…

【1691. 堆叠长方体的最大高度】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你 n 个长方体 cuboids &#xff0c;其中第 i 个长方体的长宽高表示为 cuboids[i] [widthi, lengthi, heighti]&#xff08;下标从 0 开始&#xff09;。请你从 cuboids 选出一个 子集 &#xff0c…

快速傅里叶变换及Python代码实现

一、前言 我想认真写好快速傅里叶变换&#xff08;Fast Fourier Transform&#xff0c;FFT&#xff09;&#xff0c;所以这篇文章会由浅到细&#xff0c;由窄到宽的讲解&#xff0c;但是傅里叶变换对于寻常人并不是很容易理解的&#xff0c;所以对于基础不牢的人我会通过前言普…

阿里巴巴2022年最新最全500道Java后端面试大全(值得收藏)

进大厂是大部分程序员的梦想&#xff0c;而进大厂的门槛也是比较高的&#xff0c;所以这里整理了一份阿里、美团、滴滴、头条等大厂面试大全其中概括的知识点有&#xff1a;Java基础、spring、springmvc、springboot、springcloud、JVM、Tomcat、dubbo、netty、zookeeper共有50…

Java中四大线程池应用及详解

线程池的思想 我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a; 如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&#xff0c;这样频繁创建线程就会大大降低系统的效率&a…

移动网络技术--名词介绍

GPRS网络制式&#xff08;General Packet Radio Service&#xff09;为“通用分组无线服务”&#xff0c;它是利用“包交换”&#xff08;Packet-Switched&#xff09;的概念所发展出的一套基于GSM系统的无线传输方式。 GGSN&#xff08;Gateway GPRS Supporting Node,网关GPR…

Nginx入门到弃坑---安装与使用篇(2)

1 下载 官网传送门下载传送门点击下载最新Windows-1.23版下载传送门点击下载最新Linux-1.23版下载传送门 2 Windows安装 2.1 环境介绍 下载完成后解压缩 目录如下 配置文件地址&#xff1a;.\nginx-1.23.2\conf\nginx.conf&#xff0c;默认配置的nginx监听的端口为80&…

监控系列(一)DM8+Prometheus+Grafana搭建

一、背景 近期进行适配&#xff0c;因用户统一监控平台使用的是promethesugrafanaaltermannger这一套&#xff0c;因此对达梦数据库进行适配对接。 目前主要有两种方式&#xff1a; 1. 部署Dem管理系统对外提供接口推送到prometheus进行采集数据&#xff0c;采集项可查看《De…

【云计算与大数据技术】分布式计算、虚拟化技术、并行编程技术等技术讲解(超详细必看)

一、分布式计算 分布式计算是一种计算方法&#xff0c;和集中式计算相对&#xff0c;随着计算的发展&#xff0c;一些应用需要巨大的计算能力才能完成&#xff0c;如果采用集中式计算则需要耗费很长的时间&#xff0c;而分布式计算将应用分解成许多更小的部分&#xff0c;分配…

文献阅读(195)物理设计/时序分析

文章目录物理设计时序分析题目&#xff1a;Intelligent Design Automation for 2.5/3D Heterogeneous SoC Integration时间&#xff1a;2020会议&#xff1a;ICCAD研究机构&#xff1a;国立台湾大学 本篇论文的主要贡献&#xff1a; 物理设计&#xff1a;包括RDL布线和板级布…