【muduo】进程信息

ProcessInfo.h

// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.

#ifndef MUDUO_BASE_PROCESSINFO_H
#define MUDUO_BASE_PROCESSINFO_H

#include <muduo/base/StringPiece.h>
#include <muduo/base/Types.h>
#include <muduo/base/Timestamp.h>
#include <vector>

namespace muduo
{

namespace ProcessInfo
{
  // 进程id
  pid_t pid();
  // 进程id的字符串形式
  string pidString();
  //返回实际用户的ID
  uid_t uid();
  // 进程的用户名
  string username();
  // 返回有效用户的ID。
  uid_t euid();
  // 进程开始时间
  Timestamp startTime();
  // 返回时钟频率
  int clockTicksPerSecond();
  // 返回内存页的大小
  int pageSize();
  // 是否以调试模式构建
  bool isDebugBuild();  // constexpr

  // 获取主机名称
  string hostname();
  // 获取进程名称
  string procname();
  StringPiece procname(const string& stat);

  /// read /proc/self/status
  string procStatus();

  /// read /proc/self/stat
  string procStat();

  /// read /proc/self/task/tid/stat
  string threadStat();

  /// readlink /proc/self/exe
  // 
  string exePath();

  int openedFiles();
  int maxOpenFiles();

  struct CpuTime
  {
    double userSeconds;
    double systemSeconds;

    CpuTime() : userSeconds(0.0), systemSeconds(0.0) { }
  };
  CpuTime cpuTime();

  int numThreads();
  std::vector<pid_t> threads();
}

}

#endif  // MUDUO_BASE_PROCESSINFO_H

ProcessInfo.cpp

// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)
//

#include <muduo/base/ProcessInfo.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/FileUtil.h>

#include <algorithm>

#include <assert.h>
#include <dirent.h>
#include <pwd.h>
#include <stdio.h> // snprintf
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/times.h>

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

  __thread std::vector<pid_t>* t_pids = NULL;
  int taskDirFilter(const struct dirent* d)
  {
    if (::isdigit(d->d_name[0]))
    {
      t_pids->push_back(atoi(d->d_name));
    }
    return 0;
  }

  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;
  }

  // 获取进程启动时间
  Timestamp g_startTime = Timestamp::now();
  // assume those won't change during the life time of a process.
  // 获取时钟频率
  int g_clockTicks = static_cast<int>(::sysconf(_SC_CLK_TCK));
  // 获取内存页大小
  int g_pageSize = static_cast<int>(::sysconf(_SC_PAGE_SIZE));
}
}

using namespace muduo;
using namespace muduo::detail;

//返回实际用户的ID
pid_t ProcessInfo::pid()
{
  return ::getpid();
}

string ProcessInfo::pidString()
{
  char buf[32];
  snprintf(buf, sizeof buf, "%d", pid());
  return buf;
}

uid_t ProcessInfo::uid()
{
  return ::getuid();
}

// 进程的用户名
string ProcessInfo::username()
{
  struct passwd pwd;
  struct passwd* result = NULL;
  char buf[8192];
  const char* name = "unknownuser";

  getpwuid_r(uid(), &pwd, buf, sizeof buf, &result);
  if (result)
  {
    name = pwd.pw_name;
  }
  return name;
}

// 返回有效用户的ID。
uid_t ProcessInfo::euid()
{
  return ::geteuid();
}

// 进程开始时间
Timestamp ProcessInfo::startTime()
{
  return g_startTime;
}

// 一秒的时钟数
int ProcessInfo::clockTicksPerSecond()
{
  return g_clockTicks;
}

// 返回内存页的大小
int ProcessInfo::pageSize()
{
  return g_pageSize;
}

// 是否以调试模式构建
bool ProcessInfo::isDebugBuild()
{
#ifdef NDEBUG
  return false;
#else
  return true;
#endif
}

// 获取主机名称
string ProcessInfo::hostname()
{
  // HOST_NAME_MAX 64
  // _POSIX_HOST_NAME_MAX 255
  char buf[256];
  if (::gethostname(buf, sizeof buf) == 0)
  {
    buf[sizeof(buf)-1] = '\0';
    return buf;
  }
  else
  {
    return "unknownhost";
  }
}

// 获取进程名称
string ProcessInfo::procname()
{
  return procname(procStat()).as_string();
}

StringPiece ProcessInfo::procname(const string& stat)
{
  StringPiece name;
  size_t lp = stat.find('(');
  size_t rp = stat.rfind(')');
  if (lp != string::npos && rp != string::npos && lp < rp)
  {
    name.set(stat.data()+lp+1, static_cast<int>(rp-lp-1));
  }
  return name;
}

// 通过/proc/进程id/status 文件 ,获取进程相关信息
string ProcessInfo::procStatus()
{
  string result;
  FileUtil::readFile("/proc/self/status", 65536, &result);
  return result;
}

// 通过/proc/进程id/stat 文件 ,获取进程相关信息
string ProcessInfo::procStat()
{
  string result;
  FileUtil::readFile("/proc/self/stat", 65536, &result);
  return result;
}

// 通过/proc/进程id/stat 文件 ,获取进程的线程相关信息
string ProcessInfo::threadStat()
{
  char buf[64];
  snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid());
  string result;
  FileUtil::readFile(buf, 65536, &result);
  return result;
}

// 执行路径,从根目录开始的绝对路径。 通过命令readlink打开文件/proc/进程id/exe,可以进行查看
string ProcessInfo::exePath()
{
  string result;
  char buf[1024];
  ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf);
  if (n > 0)
  {
    result.assign(buf, n);
  }
  return result;
}

// 计算打开的文件描述符的数目,可以通过命令`ll /proc/进程id/fd | wc -l`来计算得到文件描述符的数目
int ProcessInfo::openedFiles()
{
  t_numOpenedFiles = 0;
  scanDir("/proc/self/fd", fdDirFilter);
  return t_numOpenedFiles;
}

// 获取进程可以打开的最大文件描述符的数量
int ProcessInfo::maxOpenFiles()
{
  struct rlimit rl;
  if (::getrlimit(RLIMIT_NOFILE, &rl))
  {
    return openedFiles();
  }
  else
  {
    return static_cast<int>(rl.rlim_cur);
  }
}

// 获取CPU时间
ProcessInfo::CpuTime ProcessInfo::cpuTime()
{
  ProcessInfo::CpuTime t;
  struct tms tms;
  if (::times(&tms) >= 0)
  {
    const double hz = static_cast<double>(clockTicksPerSecond());
    t.userSeconds = static_cast<double>(tms.tms_utime) / hz;  // 用户时间
    t.systemSeconds = static_cast<double>(tms.tms_stime) / hz;  // 系统时间
  }
  return t;
}

// 线程数目,通过命令`cat /proc/进程id/status | grep 'Threads' 可以获得线程数目`
int ProcessInfo::numThreads()
{
  int result = 0;
  string status = procStatus();
  size_t pos = status.find("Threads:");
  if (pos != string::npos)
  {
    result = ::atoi(status.c_str() + pos + 8);
  }
  return result;
}

// 线程id,通过命令'ls /proc/进程id/task 可以获得进程中的线程号'
std::vector<pid_t> ProcessInfo::threads()
{
  std::vector<pid_t> result;
  t_pids = &result;
  scanDir("/proc/self/task", taskDirFilter);
  t_pids = NULL;
  std::sort(result.begin(), result.end());
  return result;
}

注意点

通过/proc/进程id/目录,可以获得众多进程相关的信息,这是系统提供的我们访问进程内核中参数的一个接口。

### 安装 muduo 网络库 #### 准备工作 为了成功安装 muduo 库,在 Ubuntu 上需确保已安装必要的开发工具和依赖项。特别是 Python 开发环境对于编译 Boost.Python 模块至关重要。 ```bash sudo apt-get install python-dev # 安装Python开发包以支持Boost.Python模块的构建[^1] ``` #### 安装 Boost 和 CMake muduo 依赖于 Boost 库以及 CMake 构建系统来完成其自身的编译过程: ```bash sudo apt-get update # 更新软件源列表 sudo apt-get install libboost-all-dev # 安装完整的Boost库集合 apt-get install cmake # 如果尚未安装CMake,则执行此命令进行安装 ``` #### 获取并配置 Muduo 源码 通过 GitHub 获得最新版本的 muduo 源代码,并对其进行适当调整以便顺利编译: 访问 [GitHub](https://github.com/chenshuo/muduo),下载压缩包或克隆仓库至本地机器。解压后打开 `CMakeLists.txt` 文件,建议注释掉跳过 unit_test 测试用例部分的内容,这有助于减少不必要的编译时间和资源消耗[^2]。 #### 编译与安装 Muduo 进入泥巴(muduo)项目的根目录运行如下脚本启动整个项目结构的自动创建、编译流程: ```bash ./build.sh # 启动编译进程 ./build.sh install # 尝试将编译好的二进制文件部署到指定位置 ``` 值得注意的是,默认情况下 `build.sh install` 可能不会把头文件和静态/动态链接库放置在系统的标准查找路径内(比如 `/usr/include`, `/usr/local/lib`),而是放在了特定子目录里(例如 `build/release-install-cpp11`)。因此还需要手动处理这些文件的位置问题[^3]。 可以采取两种方式解决这个问题: - **复制方法**: 使用 `cp -r build/release-install-cpp11/* /usr/local/` 命令直接将所需文件复制到全局可见区域; - **软连接方案**: 或者利用 `ln -s` 创建指向实际存储地点的快捷方式,从而让其他应用程序能够找到它们。 #### 设置环境变量 (可选) 为了让系统识别新加入的库及其对应的头文件,可以在 `.bashrc` 中追加相应的 LD_LIBRARY_PATH 和 PKG_CONFIG_PATH 条目: ```bash export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH source ~/.bashrc ``` 这样就可以正常使用 muduo 提供的功能接口编写高性能网络程序了!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值