热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自己实现Linux系统任务管理器(附源码)

自己实现Linux系统任务管理器(附源码),Go语言社区,Golang程序员人脉社

一、前言

        之前在操作系统课程中,使用Java实现的任务管理器,使用了Swing界面、Runtime、Process相关类。文章总结和程序下载在下面:

        Java调用批处理或可执行文件和Runtime、Process类实现Java版进程管理器:http://blog.csdn.net/ljheee/article/details/52067690

        Java进程管理器MyProcess.rar----免积分下载:http://download.csdn.net/detail/ljheee/9598423

        虽然基本功能实现了,Java跨平台的特性,也使得这个应用在Linux上跑,但是在实现这个版本之后就已经感觉到Java对操作系统信息的提取与封装是有限的,Process包含的进程信息有限,且操作不方便。

        因此最近在Linux课程中,决定用Qt界面+Linux方式实现自己的Linux版任务管理器。在程序设计之前,有必要先了解下Linux系统进程信息提取方式,因为这种“Linux方式”不像Java的Process类封装那样,不管底层,只管调用  process.getInputStream();去读取流。

二、Linux下/proc目录简介

        Linux内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。

        系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的 PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。

        直接打开自己安装的Linux系统,进入/proc,可以看到很多数字命名的文件夹;文件夹名的数字,代表当前运行的一个进程的PID,它是读取进程信息的接口。

Linux下/proc下其他重要目录

/proc/cpuinfo     --cpu的信息

/proc/devices     --已经加载的设备并分类

/proc/modules     --所有加载到内核的模块列表

/proc/stat        --所有的CPU活动信息,可采点计算cpu的利用率

/proc/version     --Linux内核版本和gcc版本

 

三、Qt实现Linux版任务管理器

        用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。

        我们要显示系统信息,只需进行相应的文件操作就行了。

        Qt的发展势头相当猛,qt的可移植性相当强,现在应用程序做界面基本都用Qt。Qt是诺基亚开发的一个跨平台的C++图形用户界面应用程序框架。Qt商业版只能试用30天,不过有GPL版的,可以免费使用。有一个非常不错的免费Qt集成开发环境QtCreator IDE。Linux版任务管理器采用的是Qt来实现图形界面。

步骤:

1、Linux下安装Qt Creator,打开新建一个工程,工程目录下,相关文件会有6个,具体见下图--工程文件夹:

 

编译完成后的实现效果:

“内存信息”模块:

 

“进程信息”模块:

 

“模块信息”模块:

 

“系统信息”模块:

 

“关于”模块:

 

 

完整源码如下:

main.cpp    工程运行的入口,创建工程时自动创建的,不需要修改。

#include #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }

mainwindow.h  工程头文件,定义资源和事件响应函数声明。

#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui;//界面资源类,所有的界面元素都是通过该类来调用 QTimer *timer; //计时器 private slots: void on_pushButton_pkill_clicked(); void on_pushButton_prefresh_clicked(); void on_pushButton_Model_install_clicked(); void on_pushButton_Model_remove_clicked(); void on_pushButton_Model_refresh_clicked(); void on_pushButton_reboot_clicked(); void on_pushButton_halt_clicked(); void on_tabWidget_INFO_currentChanged(int index); void timer_update_currentTabInfo(); //显示tab中的内容 void show_tabWidgetInfo(int index); }; #endif // MAINWINDOW_H

mainwindow.cpp  工程最重要的源文件,完成主要的业务逻辑。

#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include int a0 = 0, a1 = 0, b0 = 0, b1 = 0; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); timer = new QTimer(this); QWidget::connect( timer, SIGNAL( timeout() ), this, SLOT( timer_update_currentTabInfo() ) );//ui控件-事件响应 QWidget::connect( ui->tabWidget_INFO, SIGNAL( currentChanged() ), this, SLOT( on_tabWidget_currentChanged() ) ); timer->start(1000); } MainWindow::~MainWindow() { delete ui; delete timer; } void MainWindow::timer_update_currentTabInfo() { int index = ui->tabWidget_INFO->currentIndex(); //定时器只刷新内存tab页面,用于进度条动态显示 if (index == 0) { show_tabWidgetInfo(index); } } void MainWindow::show_tabWidgetInfo(int index) { QString tempStr; //读取文件信息字符串 QFile tempFile; //用于打开系统文件 int pos; //读取文件的位置 if (index == 0) //内存資源 { tempFile.setFileName("/proc/meminfo"); //打开内存信息文件 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The meminfo file can not open!"), QMessageBox::Yes); return ; } QString memTotal; QString memFree; QString memUsed; QString swapTotal; QString swapFree; QString swapUsed; int nMemTotal, nMemFree, nMemUsed, nSwapTotal, nSwapFree, nSwapUsed; while (1) { tempStr = tempFile.readLine(); pos = tempStr.indexOf("MemTotal"); if (pos != -1) { memTotal = tempStr.mid(pos+10, tempStr.length()-13); memTotal = memTotal.trimmed(); nMemTotal = memTotal.toInt()/1024; } else if (pos = tempStr.indexOf("MemFree"), pos != -1) { memFree = tempStr.mid(pos+9, tempStr.length()-12); memFree = memFree.trimmed(); nMemFree = memFree.toInt()/1024; } else if (pos = tempStr.indexOf("SwapTotal"), pos != -1) { swapTotal = tempStr.mid(pos+11, tempStr.length()-14); swapTotal = swapTotal.trimmed(); nSwapTotal = swapTotal.toInt()/1024; } else if (pos = tempStr.indexOf("SwapFree"), pos != -1) { swapFree = tempStr.mid(pos+10,tempStr.length()-13); swapFree = swapFree.trimmed(); nSwapFree = swapFree.toInt()/1024; break; } } nMemUsed = nMemTotal - nMemFree; nSwapUsed = nSwapTotal - nSwapFree; memUsed = QString::number(nMemUsed, 10); swapUsed = QString::number(nSwapUsed, 10); memFree = QString::number(nMemFree, 10); memTotal = QString::number(nMemTotal, 10); swapFree = QString::number(nSwapFree, 10); swapTotal = QString::number(nSwapTotal, 10); ui->label_RAM_Used->setText(memUsed+" MB"); ui->label_RAM_Left->setText(memFree+" MB"); ui->label_RAM_Total->setText(memTotal+" MB"); ui->label_SWAP_Used->setText(swapUsed+" MB"); ui->label_SWAP_Left->setText(swapFree+" MB"); ui->label_SWAP_Total->setText(swapTotal+" MB"); ui->progressBar_RAM->setValue(nMemUsed*100/nMemTotal); ui->progressBar_SWAP->setValue(nSwapUsed*100/nSwapTotal); tempFile.close(); //关闭内存信息文件 int tt = 2; //取2个点采样计算cpu当前利用律 int cpuInfo[2][7]; int cpuTotal[2][2]; while (tt) { tempFile.setFileName("/proc/stat"); //打开CPU使用状态信息 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The stat file can not open!"), QMessageBox::Yes); return; } tempStr = tempFile.readLine(); for (int i = 0; i <7; i++) { cpuInfo[2-tt][i] = tempStr.section(" ", i+1, i+1).toInt(); cpuTotal[1][2-tt] += cpuInfo[2-tt][i]; if (i == 3) { cpuTotal[0][2-tt] += cpuInfo[2-tt][i]; } } tt--; tempFile.close(); //关闭stat文件 } int a = cpuTotal[0][1] - cpuTotal[0][0]; int b = cpuTotal[1][1] - cpuTotal[1][0]; if (a <0) { a = -a; } if (b <0) { b = -b; } ui->progressBar_CPU->setValue(a*100/b); tempFile.setFileName("/proc/stat"); //linux下用/proc/stat文件来计算cpu的利用率 //这个文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The stat file can not open!"), QMessageBox::Yes); return; } tempStr = tempFile.readLine(); a0 = a1; b0 = b1; a1 = b1 = 0; int gg; for (int i = 0; i <7; i++) { b1 += tempStr.section(" ", i+2, i+2).toInt(); gg = b1; if (i == 3) { a1 += tempStr.section(" ", i+2, i+2).toInt(); } } int m, n; m = a1 - a0; n = b1 - b0; if (m <0) { m = -m; } if (n <0) { n = -n; } ui->progressBar_CPU->setValue( (n-m)*100/n ); tempFile.close(); //关闭stat文件 } else if (index == 1) //进程信息 { ui->listWidget_process->clear(); QDir qd("/proc"); QStringList qsList = qd.entryList(); QString qs = qsList.join("n"); QString id_of_pro; bool ok; int find_start = 3; int a, b; int nProPid; //进程PID int number_of_sleep = 0, number_of_run = 0, number_of_zombie = 0; int totalPrOnum= 0; //进程总数 QString proName; //进程名 QString proState; //进程状态 QString proPri; //进程优先级 QString proMem; //进程占用内存 QListWidgetItem *title = new QListWidgetItem("PIDt" + QString::fromUtf8("名称") + "tt" + QString::fromUtf8("状态") + "t" + QString::fromUtf8("优先级") + "t" + QString::fromUtf8("占用内存"), ui->listWidget_process); //循环读取进程 while (1) { //获取进程PID a = qs.indexOf("n", find_start); b = qs.indexOf("n", a+1); find_start = b; id_of_pro = qs.mid(a+1, b-a-1); totalProNum++; nProPid = id_of_pro.toInt(&ok, 10); if(!ok) { break; } //打开PID所对应的进程状态文件 tempFile.setFileName("/proc/" + id_of_pro + "/stat"); if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The pid stat file can not open!"), QMessageBox::Yes); return; } tempStr = tempFile.readLine(); if (tempStr.length() == 0) { break; } a = tempStr.indexOf("("); b = tempStr.indexOf(")"); prOname= tempStr.mid(a+1, b-a-1); proName.trimmed(); //删除两端的空格 proState = tempStr.section(" ", 2, 2); proPri = tempStr.section(" ", 17, 17); proMem = tempStr.section(" ", 22, 22); switch ( proState.at(0).toLatin1() ) { case 'S': number_of_sleep++; break; //Sleep case 'R': number_of_run++; break; //Running case 'Z': number_of_zombie++; break; //Zombie default : break; } if (proName.length() >= 12) { QListWidgetItem *item = new QListWidgetItem(id_of_pro + "t" + proName + "t" + proState + "t" + proPri + "t" + proMem, ui->listWidget_process); } else { QListWidgetItem *item = new QListWidgetItem(id_of_pro + "t" + proName + "tt" + proState + "t" + proPri + "t" + proMem, ui->listWidget_process); } } QString temp; temp = QString::number(totalProNum, 10); ui->label_pNum->setText(temp); temp = QString::number(number_of_run, 10); ui->label_pRun->setText(temp); temp = QString::number(number_of_sleep, 10); ui->label_pSleep->setText(temp); temp = QString::number(number_of_zombie, 10); ui->label_pZombie->setText(temp); tempFile.close(); //关闭该PID进程的状态文件 } else if (index == 2) //模块信息 { ui->listWidget_model->clear(); //sys/module 是一个 sysfs 目录层次, 包含当前加载模块的信息. /proc/moudles 是旧式的, 那种信息的单个文件版本. 其中的条目包含了模块名, 每个模块占用的内存数量, 以及使用计数. 另外的字串追加到每行的末尾来指定标志, 对这个模块当前是活动的. tempFile.setFileName("/proc/modules"); //打开模块信息文件 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The modules file can not open!"), QMessageBox::Yes); return ; } //设置模块首行项目 QListWidgetItem *title = new QListWidgetItem( QString::fromUtf8("名称") + "ttt" + QString::fromUtf8("使用内存数") + "tt" + QString::fromUtf8("使用次數"), ui->listWidget_model); QString mod_Name, mod_Mem, mod_Num; //循环读取文件内容,查找需要的信息 while (1) { tempStr = tempFile.readLine(); if (tempStr.length() == 0) { break; } mod_Name = tempStr.section(" ", 0, 0); mod_Mem = tempStr.section(" ", 1, 1); mod_Num = tempStr.section(" ", 2, 2); if (mod_Name.length() > 10) { QListWidgetItem *item = new QListWidgetItem(mod_Name + "tt" + mod_Mem + "tt" + mod_Num, ui->listWidget_model); } else { QListWidgetItem *item = new QListWidgetItem(mod_Name + "ttt" + mod_Mem + "tt" + mod_Num, ui->listWidget_model); } } tempFile.close(); //关闭模块信息文件 } else if (index == 3) //系统信息 { //int ok; tempFile.setFileName("/proc/cpuinfo"); //打开CPU信息文件 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The cpuinfo file can not open!"), QMessageBox::Yes); return; } //循环读取文件内容,查找需要的信息 while (1) { tempStr = tempFile.readLine(); //QMessageBox::warning(this, tr("msg"), tempStr, QMessageBox::Yes); if(tempStr==NULL){//文件读完,跳出 break; } pos = tempStr.indexOf("model name"); if (pos != -1) { pos += 13; //跳过前面的"model name:"所占用的字符 QString *cpu_name = new QString( tempStr.mid(pos, tempStr.length()-13) ); ui->label_CPUName->setText(*cpu_name); } else if (pos = tempStr.indexOf("vendor_id"), pos != -1) { pos += 12; //跳过前面的"vendor_id:"所占用的字符 QString *cpu_type = new QString( tempStr.mid(pos, tempStr.length()-12) ); ui->label_CPUType->setText(*cpu_type); } else if (pos = tempStr.indexOf("cpu MHz"), pos != -1) { pos += 11; //跳过前面的"cpu MHz:"所占用的字符 QString *cpu_frq = new QString( tempStr.mid(pos, tempStr.length()-11) ); double cpufrq = cpu_frq->toDouble(); //4核CPU cpu_frq->setNum(cpufrq*4); ui->label_CPUFrequency->setText(*cpu_frq + " HZ"); } else if (pos = tempStr.indexOf("cache size"), pos!=-1) { pos += 13; //跳过前面的"cache size:"所占用的字符 QString *cache_size = new QString( tempStr.mid(pos, tempStr.length()-16) ); int cachesize = cache_size->toInt(); //4核CPU cache_size->setNum(cachesize*4); ui->label_CatheCapacity->setText(*cache_size + " KB"); } else //跳过其他的内容 { } } tempFile.close(); //关闭CPU信息文件 //打开操作系统信息文件 tempFile.setFileName("/proc/version"); if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The version file can not open!"), QMessageBox::Yes); return ; } tempStr = tempFile.readLine(); pos = tempStr.indexOf("version"); QString *os_version = new QString( tempStr.mid(0, pos-1) ); ui->label_SystemType->setText(*os_version); int pos1 = tempStr.indexOf("("); QString *os_type = new QString( tempStr.mid(pos, pos1-pos-1) ); ui->label_SystemVersion->setText(*os_type); pos = tempStr.indexOf("gcc version"); pos1 = tempStr.indexOf("#"); QString *gcc_info = new QString( tempStr.mid(pos+12, pos1-pos-14) ); ui->label_GCCVersion->setText(*gcc_info); tempFile.close(); //关闭操作系统信息文件 } else //说明 { } return; } void MainWindow::on_pushButton_halt_clicked() { system("halt"); } void MainWindow::on_pushButton_reboot_clicked() { system("reboot"); } void MainWindow::on_tabWidget_INFO_currentChanged(int index) { show_tabWidgetInfo(index); //显示tab中的内容 return ; } //杀死进程 void MainWindow::on_pushButton_pkill_clicked() { //获得进程号 QListWidgetItem *item = ui->listWidget_process->currentItem(); QString pro = item->text(); pro = pro.section("t", 0, 0); system("kill " + pro.toLatin1()); QMessageBox::warning(this, tr("kill"), QString::fromUtf8("该进程已被杀死!"), QMessageBox::Yes); //回到进程信息tab表 show_tabWidgetInfo(1); } //刷新进程信息 void MainWindow::on_pushButton_prefresh_clicked() { show_tabWidgetInfo(1); } void MainWindow::on_pushButton_Model_install_clicked() { show_tabWidgetInfo(2); //安装模块还不知道如何实现 QMessageBox::warning(this, tr("tip"), tr("安装模块还不知道如何实现"), QMessageBox::Yes); } void MainWindow::on_pushButton_Model_remove_clicked() { show_tabWidgetInfo(2); //卸载模块还不知道如何实现 QMessageBox::warning(this, tr("tip"), tr("卸载模块还不知道如何实现"), QMessageBox::Yes); } void MainWindow::on_pushButton_Model_refresh_clicked() { show_tabWidgetInfo(2); QMessageBox::warning(this, tr("tip"), tr("刷新模块还不知道如何实现"), QMessageBox::Yes); }

Mainwindow.ui 工程界面文件。

MainWindow

0 0 605 438

MainWindow

0 -10 611 341

WaitCursor

QTabWidget::Triangular

3

false

内存信息

内存信息

内存信息

0 0 591 81

CPU

50 30 431 23

24

0 30 66 17

CPU:

0 80 591 231

内存和交换分区

50 50 431 23

24

50 140 431 23

24

0 50 66 17

内存:

0 140 66 17

交换

50 80 66 17

Used:

200 80 66 17

Left:

380 80 66 17

Total:

380 170 66 17

Total:

50 170 66 17

Used:

200 170 66 17

Left:

90 80 66 17

0

240 80 66 17

0

420 80 66 17

0

420 170 66 17

0

90 170 66 17

0

240 170 66 17

0 进程信息

0 0 421 271

20 280 98 27

kill

170 280 98 27

refresh

430 30 66 17

进程数:

490 30 66 17

0

430 60 66 17

运行数:

430 100 66 17

睡眠数:

430 140 66 17

浆死数:

490 60 66 17

0

490 100 66 17

0

490 140 66 17

0 模块信息

20 280 98 27

Install

180 280 98 27

Romove

350 280 98 27

refresh

0 0 561 271 系统信息

0 0 591 171

处理器信息

50 30 66 17

CPU名称:

50 60 66 17

CPU类型:

50 90 66 17

CPU频率:

50 120 81 17

Cache大小:

140 30 321 17

未知

140 60 151 17

未知

140 90 66 17

未知

140 120 66 17

未知

0 180 591 121

操作系统信息

70 30 111 17

操作系统类型:

70 60 111 17

操作系统版本:

70 90 111 17

GCC编译器:

190 30 151 17

未知

190 60 281 17

未知

190 90 291 17

未知 关于

20 30 66 17

项目名:

100 30 191 17

Linux下Qt实现任务管理器

100 70 191 17

ljheee

20 70 66 17

作者:

100 110 191 17

2017-4-10

20 110 66 17

时间:

100 150 191 17

QQ554278334

20 150 66 17

联系:

380 340 98 27

reboot

500 340 98 27

shutdown

0 0 605 26

SysMontior TopToolBarArea false

 Qt实现Linux任务管理器SysMonitor.ziphttp://download.csdn.net/detail/ljheee/9817990

 

 

 

 

 

 

 


推荐阅读
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • C++中的三角函数计算及其应用
    本文介绍了C++中的三角函数的计算方法和应用,包括计算余弦、正弦、正切值以及反三角函数求对应的弧度制角度的示例代码。代码中使用了C++的数学库和命名空间,通过赋值和输出语句实现了三角函数的计算和结果显示。通过学习本文,读者可以了解到C++中三角函数的基本用法和应用场景。 ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
author-avatar
Yunir_944
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有