muduo网络库源码复现笔记(十五):base库的ProcessInfo.h

Muduo网络库简介

muduo 是一个基于 Reactor 模式的现代 C++ 网络库,作者陈硕。它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。
muduo网络库的核心代码只有数千行,在网络编程技术学习的进阶阶段,muduo是一个非常值得学习的开源库。目前我也是刚刚开始学习这个网络库的源码,希望将这个学习过程记录下来。这个网络库的源码已经发布在GitHub上,可以点击这里阅读。目前Github上这份源码已经被作者用c++11重写,我学习的版本是没有使用c++11版本的。不过二者大同小异,核心思想是没有变化的。点这里可以看我的源代码,如果你对我之前的博客有兴趣,可以点击下面的连接:
muduo网络库源码复现笔记(一):base库的Timestamp.h
muduo网络库源码复现笔记(二):base库的Atomic.h
muduo网络库源码复现笔记(三):base库的Exception.h
muduo网络库源码复现笔记(四):base库的Thread.h和CurrentThread.h
muduo网络库源码复现笔记(五):base库的Mutex.h和Condition.h和CoutntDownLatch.h
muduo网络库源码复现笔记(六):base库的BlockingQueue.h和BoundedBlockingQueue.h
muduo网络库源码复现笔记(七):base库的ThreadPool.h
muduo网络库源码复现笔记(八):base库的Singleton.h
muduo网络库源码复现笔记(九):base库的ThreadLocalSingleton.h
muduo网络库源码复现笔记(十):base库的ThreadLocalSingleton.h
muduo网络库源码复现笔记(十一):base库的StringPiece.h
muduo网络库源码复现笔记(十二):base库的LogStream.h
muduo网络库源码复现笔记(十三):base库的Logging.h
muduo网络库源码复现笔记(十四):base库的FileUtil.h

1 ProcessInfo.h

ProcessInfo.h里面定义实现了一些关于读取进程信息的函数。在讲解具体代码之前,让我们复习一下有关的知识。

1.1 /proc文件系统

许多现代的unix系统实现提供了一个/proc虚拟文件系统。这个文件系统驻留于/proc目录,并包含了各种用于展示内核信息的文件,并允许进程通过常规I/O系统读取。需要注意的是/proc下保存的文件与子目录并非存储与磁盘,而是由内核在进程访问此类信息时动态创建的。

1.1.1获取与进程有关的信息:/proc/PID

对于系统中每个进程,内核提供了相应的目录,命名为/proc/PID,其中PID是进程ID。此目录下的文件与子目录包含了进程的相关信息。如查看/proc/1目录下文件可以查看init进程的信息。

/proc/PID/fd目录

/proc/PID/fd目录为进程打开的每个文件描述符包含了一个符号连接,每个符号连接的名称与描述符的数值相匹配。每个进程可以通过/proc/self来访问自己的/proc/PID目录。

/proc/PID/task

Linux2.4增加了线程组的概念。线程组中一些属性对于线程是唯一的,所以Linux2.4在/proc/PID目录下增加了task子目录。针对进程中每个线程,内核提供/proc/PID/task/TID命名的子目录(TID是线程id)。

1.1.2 访问/proc文件

通常使用shell脚本来访问/proc目录下的文件,也可以使用I/O系统,但注意许多文件是只读的。

1.2 获取用户和组的信息

1.2.1从密码文件获取记录

使用函数getpwnam()和getpwuid()的作用是从密码文件中获取记录。

struct passwd *getpwnam(const char *name)
struct passwd *getpwuid(uid_t uid)

参数name是一个登录名,getpwnam()会返回一个指针,指向如下类型结构

struct passwd 
{ 
    char * pw_name; /* Username, POSIX.1 */ 
    char * pw_passwd; /* Password */ 
    __uid_t pw_uid; /* User ID, POSIX.1 */ 
    __gid_t pw_gid; /* Group ID, POSIX.1 */ 
    char * pw_gecos; /* Real Name or Comment field */ 
    char * pw_dir; /* Home directory, POSIX.1 */ 
    char * pw_shell; /* Shell Program, POSIX.1 */ 
}; 

1.3头文件内容

在ProcessInfo.h头文件中定义了一些处理进程信息的函数如下,函数作用如注释所示。下面讲解其中几个函数

namespace ProcessInfo
{
	pid_t pid();//返回进程pid
	string pidString();//将进程pid字符串化
	uid_t uid();//返回uesrId
	string username();//返回用户姓名
	uid_t euid();
	Timestamp startTime();//时间戳
	
	string hostname();
	//read /proc/self/status
	string procStatus();//读取进程状态
	int openedFiles();//统计进程打开的文件数目
	int maxOpenFiles();
	
	int numThreads();
	std::vector threads();
}

1.3.1 maxOpenFiles()

这个函数用于查询进程允许打开的最大文件数。结构体rlimit是描述资源软硬限制的结构体。rlim_cur是软上限,rlim_max是硬上限。软限制是内核强加给相应资源的限制值,硬限制是软限制的最大值。

struct rlimit {
  rlim_t rlim_cur;
  rlim_t rlim_max;
};

getrlimit函数调用成功的话,返回零,则返回软上限;否则调用openedFiles()返回目前打开的文件数目,下面说一下openedFiles()。

int ProcessInfo::maxOpenFiles()
{
	struct rlimit rl;
	if(::getrlimit(RLIMIT_NOFILE,&rl))
	{
		return openedFiles();
	}
	else
	{
		return static_cast(rl.rlim_cur);
	}
}

1.3.2 openedFiles()

这个函数用于统计打开文件的数目,它的关键是被封装的scanDir函数。t_numOpenedFiles是一个全局变量,也是线程局部存储数据。

int ProcessInfo::openedFiles()
{
	t_numOpenedFiles = 0;
	scanDir("/proc/self/fd",fdDirFilter);
	return t_numOpenedFiles;
}

scanDir的实现如下,struct dirent为了获取某文件夹目录内容,所使用的结构体。filter是一个函数指针,起到过滤作用,alphasort用于排序。

int scanDir(const char *dirpath,int (*filter)(const struct dirent *))
	{
		struct dirent** namelist = NULL;
		int result = ::scandir(dirpath,&namelist,filter,alphasort);
		assert(namelist == NULL);
		return result;
	}

关于filter可以自己定义,比如在openedFiles()用了fdDirFilter来获取/proc/self/fd下目录的个数。由于fd下的目录均以数字打头,我们可以定义
fdDirFilter:

int fdDirFilter(const struct dirent* d)
	{
		if(::isdigit(d->d_name[0]))
		{
			++t_numOpenedFiles;
		}
		return 0;
	}

你可能感兴趣的:(muduo)