深度系统装机大师LINUX 系统看机出现这个画面是什么意思?怎么解决?求大神指点。。。谢谢

在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
想往linux方面学习一下,本人是刚毕业的PHPer
在虚拟机里玩过一阵子Ubuntu,感觉还可以
最近在网友的安利下看到了Deepin深度操作系统,看起来不错,请问有人用过吗?
我准备在我的闲置i3笔记本里装一个,各位有什么建议吗?
先谢过各位
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
个人就是从10.04到14.04一直都是用Ubuntu系列的5年支持的LTS版本,也推荐新人用Ubuntu Kylin和Linux Deepin这些专门为中国人设计的Linux桌面,中文语言包,搜狗输入法,WPS都一应俱全,不需要新手去折腾.
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
Ubuntu和Debian都不是对新手很友好…建议直接使用那种开箱即用的包比如基于Ubuntu的mint基于arch的manjaro,这个强烈推荐
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
个人建议,小白用户或者想用linux完成自己工作的人员,还是用deepin吧,这样你不用费劲去折腾装QQ,装输入法,装各种常用软件,这些deepin都为你做好了。你可以把所有精力放在你自己要做的事情,比如php开发,Android开发,各种开发。普通人可以尽情的销售上网娱乐,玩游戏。有很多人思想还停留在以前,认为折腾个输入法,折腾个QQ就是真的会用linux了。其实这是没有意义的,如果真的要了解linux,学以致用,应该去学linux运维,而不是折腾这些常用软件。你可以在deepin的终端敲命令,体验运维的视角。也可以安装虚拟机,装个服务器版的linux,去链接学习运维。不要把精力放在折腾一些没有意义的事情上,比如装输入法,QQ不要把精力放在折腾一些没有意义的事情上,比如装输入法,QQ不要把精力放在折腾一些没有意义的事情上,比如装输入法,QQ重要的事情说3遍,好用不是错,好用不用瞎折腾浪费精力才是错。推荐deepin,我用了2年了,没有返回windows,现在某些方面比苹果mac还好用,比如深度终端
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
Deepin用着还挺不错的,基于Debian ,还有QQ等可以使用,UbuntuGUI比起深度差点,其他没啥区别了,
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
ubuntu,老师给我们讲课都用的这个,保留了很多linux原汁原味的东西哩
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
Ubuntu和deepin都用过,我承认我也非常喜欢deepin的GUI,但是,deepin稳定性差,硬件要求比较高,我有碰到安装了卡死在桌面。相对来说Ubuntu稳定一点。Ubuntu kylin也装过,这中国版非常符合国人的需求,因为预装的软件非常本地化,但是感觉稳定性还是差点。如果你觉得用deepin是因为GUI 的话,其实其他Linux也可以弄得很好看。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
这两个都是很方便,但是只是方便使用,要学习还是需要折腾。我一直用的基于Ubuntu的Mint,没那么方便,但是折腾起来很有意思
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
作为新手用户我推荐deepin,相对美观简单易用,和Ubuntu一样基于debian.不存在说要学习就用这个,要折腾就用那个.最终系统只是个工具.我们能使用它达到目的就可以了.
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
也推荐deepin,天天折腾,ubuntu、opensuse,deepin换来换去,还是deepin省心
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。深度系统安装过程中,一直在这个画面不动怎么处理?
在这画面多久了?
系统有问题,建议你使用“装机员系统”比较稳定和流畅,如果有问题可以里面发帖。
有可能是显卡驱动的问题,XP里面包含了一些硬件驱动,无意中都给装上了,可是不适合你得显卡,你开机一直按F8,进安全模式,把显卡驱动卸载尝试下
可以参照教程重装系统,深度技术已经没有再做win7系统了,现在的深度技术的win7是其他的小团队做的,兼容性和稳定性很一般。
感谢您为社区的和谐贡献力量请选择举报类型
经过核实后将会做出处理感谢您为社区和谐做出贡献
确定要取消此次报名,退出该活动?
请输入私信内容:深度定制的操作系统是什么意思?为什么厂商都喜欢定制操作系统?
互联网 & 07-27 16:42:52 & 作者:佚名 &
深度定制操作系统一般只会在手机市场上面出现,那么什么是深度定制的操作系统?同时为什么厂商都喜欢定制操作系统呢?针对此类问题,本文就为大家进行解答
我们进行手机测评时,经常会看见深度定制的操作系统,像备受好评的小米MIUI系统,华为emotion系统都属于这个范畴。那究竟什么是深度定制的操作系统?为什么厂商都喜欢定制操作系统?下面,小编将为大家解析。
什么是深度定制的操作系统?
答:定制操作系统是相对于原生操作系统来说的,某些开源的操作系统,例如Linux和Android允许终端厂商免费使用,终端厂商可以在其基础上做一些修改,以达到自身的一些目的。
根据对操作系统修改的程度,可以分为一般的定制和深度定制。定制一套自己的UI界面这样的属于一般的定制,对原生系统的改动很小,同时也很容易兼容原生应用。有些厂商却对系统的更深层做了修改。
手机操作系统可以分为内核层、中间层和应用层。基于Linux操作系统进行定制的系统,底层就是Linux系统的内核,中间层包含了名为Dalvik的JAVA虚拟机,应用层则是根据原生系统修改后加入的各种应用。每个应用程序都运行在自己的进程上,享有Dalvik虚拟机为它分配的专有实例。
所谓深度定制,一般是指对中间层做修改,就是修改Dalvik虚拟机的一些设置。例如OMS操作系统集成了大量的增强型中间件,以更好地支持各种应用,并不是简单复制安卓系统。
为什么厂商喜欢定制操作系统?
答:因为操作系统本身最大的特点并不是定制,是通用性。而国内厂商无力研发全新的操作系统,或者尝试研发但是都不够成功,那么退而求其次,选择定制的操作系统来兼容市场上已有的大量应用,同时通过适度修改来满足自身的应用集成需求,这种选择是合理的,一定程度上讲也是必然的。
其实谷歌Android操作系统也是基于Linux开源操作系统的内核而设计的&深度定制&操作系统,只是其对改动比较大,内核部分也做了修改,因此可以说是一套独立的操作系统。
国内厂商也曾尝试做独立操作系统,例如阿里云。虽然也使用了Linux的系统内核,但是阿里巴巴开发了自有的虚拟机,在中间件层面做了比较大的修改。这也是阿里巴巴宣称阿里云 OS 是独立于 Android 之外的独立操作系统的原因。
但是阿里云操作系统又兼容了Android的Dalvik,也正是如此,谷歌才反驳称,阿里云OS是经安卓系统修改而来,直接使用了安卓的运行环境、框架和工具,并不是独立的操作系统。因此,谷歌指责阿里云操作系统抄袭,要求阿里云必须与Android保持兼容。
为了对阿里巴巴施压,谷歌表示将会解除与阿里巴巴Android产品的合作和相关技术授权。阿里巴巴不得不推迟了原定的与宏碁的合作。
谷歌对于深度定制的态度,虽然没有明确表示反对,但是也并不支持,而且提出了明确的要求,就是必须通过操作系统的兼容性测试(CTS)。通过CTS测试之后便允许在设备上使用Android商标,它标志着该设备能够良好兼容软件市场中的大量应用程序。基于安卓进行深度定制的国内厂商必须满足这一要求。
某些厂商直接基于Linux系统进行定制,但是一般也需要兼容安卓系统的应用,一方面便于开发者的应用迁移,构建生态体系,另一方面也是满足操作系统的通用性这一&硬需求&,因为,谁让国内厂商无法研发出一款强大的自主操作系统呢。
大量定制操作系统的存在,造成了安卓碎片化的局面。谷歌并不希望厂商这么做。但是本身安卓又是一套开源的操作系统,而且谷歌从扩大安卓市场占有率的角度着想,仍然进行了放任。这也是安卓系统比较混乱的原因之一。
从终端厂商来讲,基于安卓的深度定制的操作系统会受到谷歌更新的制约,必须在更新上与安卓进行同步,由于安卓更新频率很快,而且变动难以预料,深度定制的系统也有一定的风险。
深度定制操作系统不限于安卓等手机系统,也包括一些电脑操作系统,这要取决于终端厂商,像Linux和Android就是允许终端厂商免费使用,但Windows系统目前还没有开放使用权,所以也就不存在基于Windows深度定制操作系统。一些高级程序员就可以基于这些系统进行修改编程,感兴趣的朋友也可以去试试。
大家感兴趣的内容
12345678910
最近更新的内容深度系统监视器原理剖析 - 简书
深度系统监视器原理剖析
为什么要做深度系统监视器?
为了达到深度操作系统UI/UX大统一的‘雄伟’目标,闲来无事写了深度系统监视器,先发一张图镇楼,哈哈哈。
深度截图_桌面_45.png
社区的开源爱好者马上会跳出来说,深度你们又造轮子,你们造的轮子比Gnome和KDE的系统监视器好吗?
回答当然是肯定的,如果不秒杀Gnome的系统监视器我造它干嘛呢?
深度系统监视器首先要解决的问题是:提高用户操作的易用性
Gnome的系统监视器默认分开了三个标签,把进程列表和资源总览分开了,看进程列表的状态就不知道资源总览的信息,看资源总览信息就不知道进程列表的状态,而且还在第三个标签提供了一个鸡肋的磁盘设备的空间,只能看啥操作都不能做,还不如放在文件管理器或者磁盘管理工具里面。
深度截图_桌面_45.png
深度截图_桌面_15.png
所以针对这些不爽的设计,深度系统监视器把资源总览信息和列表的进程信息放在一起,一眼就可以知道现在电脑的整体负载,而且用户马上就可以在右边查看高资源占用的进程,再也不用来回费劲的切换标签去看这两个本来就应该在一起的信息。
其次,深度系统监视器狠下内功,不但可以对每个进程的CPU、内存状态进行监控,还可以实时查看每个进程的磁盘IO操作和网络操作,一眼就知道哪些进程在狂写硬盘和在后台偷偷下载了。
最后,还提供一些小贴心的功能,比如查找进程启动命令所在的位置(甚至包括Wine程序都可以轻松找到)和类似xkill的功能(点哪杀哪)。
技术原理剖析
今天主要和大家分享一下对进程信息进行监听的原理和实现。
在Linux中,计算机的所有数据的计算都通过读取分析 /proc 文件系统来实现,Linux内核会实时把硬件的状况更新到 /proc 这个内存文件系统中。
下面我们就针对 /proc 不同的部分进行原理和技术实现剖析:
计算总CPU数据
得到计算机的总CPU数据比较简单,直接读取 /proc/stat 文件即可,比如在终端中执行命令
cat /proc/stat
即可得到下面的输出:
cpu0 660 51 0
cpu1 276 85 0 350 0 0 0
cpu2 603 21 0 678 0 0 0
cpu3 10 82 0 143 0 0 0
cpu4 240 70 0 215 0 0 0
cpu5 18 58 0 77 0 0 0
cpu6 967 12 0 139 0 0 0
cpu7 90 6 0 55 0 0 0
0 29 0 1 0 0 0 0 35 0 0 22 974 627 23
746 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
processes 36267
procs_running 4
procs_blocked 0
659 0 0 0 3659003
第一行就是总CPU的占用率,下面的CPU1、CPU2等等表示多核CPU某个核的CPU占有率。
第一行从左到右的数值分别表示:user, nice, system, idle, iowait, irq, softirq, steal, guest, guestnice (这些值分别代表的意义在man手册里面都有讲,今天就不展开了)
计算总CPU的占有率,首先要计算 workTime和totalTime:
workTime = user + nice +
totalTime =
return user + nice + system + idle + iowait + irq + softirq +
比如我们系统监视器2秒中获取一些当前CPU时间的切片,最后计算CPU占有率的公式就是:
cpuPercent = (currentWorkTime - prevWorkTime) * 100.0 / (currentTotalTime - prevTotalTime)
currentWorkTime和currentTotalTime表示当前的CPU时间
prevWorkTime和prevTotalTime表示2秒前的CPU时间
取得CPU时间的代码实现如下:
unsigned long long getTotalCpuTime(unsigned long long &workTime)
FILE* file = fopen("/proc/stat", "r");
if (file == NULL) {
perror("Could not open stat file");
char buffer[1024];
unsigned long long user = 0, nice = 0, system = 0, idle = 0;
// added between Linux 2.5.41 and 2.6.33, see man proc(5)
unsigned long long iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guestnice = 0;
char* ret = fgets(buffer, sizeof(buffer) - 1, file);
if (ret == NULL) {
perror("Could not read stat file");
fclose(file);
fclose(file);
sscanf(buffer,
%16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
&user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guestnice);
workTime = user + nice +
// sum everything up (except guest and guestnice since they are already included
// in user and nice, see http://unix.stackexchange.com/q/26)
return user + nice + system + idle + iowait + irq + softirq +
具体可以参考:
计算总内存数据
计算机总内存的数据保存在 /proc/meminfo 文件中,你可以通过:
cat /proc/meminfo
得到类似下面的信息:
8056276 kB
MemAvailable:
4861656 kB
4613124 kB
SwapCached:
3455196 kB
3220984 kB
Active(anon):
1932732 kB
Inactive(anon):
Active(file):
1522464 kB
Inactive(file):
2484508 kB
Unevictable:
SwapTotal:
Writeback:
AnonPages:
1919408 kB
SReclaimable:
SUnreclaim:
KernelStack:
PageTables:
NFS_Unstable:
WritebackTmp:
CommitLimit:
Committed_AS:
8831548 kB
VmallocTotal:
VmallocUsed:
VmallocChunk:
HardwareCorrupted:
AnonHugePages:
ShmemHugePages:
ShmemPmdMapped:
HugePages_Total:
HugePages_Free:
HugePages_Rsvd:
HugePages_Surp:
Hugepagesize:
DirectMap4k:
DirectMap2M:
8032256 kB
DirectMap1G:
或者通过命令 free 得到类似的输出:
buff/cache
计算内存的占有就要简单的很多:
memoryPercent = (total - available) * 100.0 / total
注意,当前系统使用的内存是由内存总量total减去可用内存aviailable的值来计算的,不能用
memoryPercent = used * 100.0 / total
因为 used 的值不包括一些被内核占用并且永不释放的缓存内存,如果用 used 的方式来计算内存百分比,会发现最终计算的结果会比实际占用的内存小 15% 左右。
具体的代码实现,我们用 libprocps-dev 这个开发库提供的 meminfo() 函数,然后直接读取 kb_main_total 和 kb_main_available 就可以了,交换空间读取 kb_swap_used 和 kb_swap_total 这两个变量的值。
参考代码实现如下:
meminfo();
memoryPercent = (kb_main_total - kb_main_available) * 100.0 / kb_main_total
swapPercent = kb_swap_used * 100.0 / kb_swap_total
计算总网络数据
计算机总网络数据可以通过读取分析 /proc/net/dev 文件来计算, 执行命令后
cat /proc/net/dev
可以得到类似的数据:
face |bytes
packets errs drop fifo frame compressed multicast|bytes
packets errs drop fifo colls carrier compressed
这个文件的每一行是一个网络设备,我们需要获得网络设备的第一个和第九个值,第一个值表示下载的总byte数,第九个值表示上传的总byte数。
原理就是读取 /proc/net/dev 的网络设备的下载和上传数据,加在一起求和,同时要排除 lo 这个虚拟网络设备,具体的代码实现如下:
void getNetworkBandWidth(unsigned long long int &receiveBytes, unsigned long long int &sendBytes)
buf = (char *) calloc(255, 1);
bufsize = 255;
devfd = fopen("/proc/net/dev", "r");
// Ignore the first two lines of the file.
fgets(buf, bufsize, devfd);
fgets(buf, bufsize, devfd);
receiveBytes = 0;
sendBytes = 0;
while (fgets(buf, bufsize, devfd)) {
unsigned long long int rBytes, sB
char *line = strdup(buf);
dev = strtok(line, ":");
// Filter lo (virtual network device).
if (QString::fromStdString(dev).trimmed() != "lo") {
sscanf(buf + strlen(dev) + 2, "%llu %*d %*d %*d %*d %*d %*d %*d %llu", &rBytes, &sBytes);
receiveBytes += rB
sendBytes += sB
free(line);
fclose(devfd);
free(buf);
这样,我们只用每2秒计算一下内存的总上传和下载byte数就可以得知系统总共下载和上传的带宽,总的上传和下载速度就更简单了:
downloadSpeed = (currentDownloadBytes - prevDownloadBytes) / 1024.0
uploadSpeed = (currentUploadBytes - prevUploadBytes) / 1024.0
计算进程的CPU和内存数据
计算进程的CPU比较简单,类似总CPU的计算方式,只是用进程自己的CPU值来计算, 进程自己的CPU值通过读取 /proc/pid/stat 来读取。
进程的内存信息也是从 /proc/pid/stat 文件中读取。
具体的代码实现请参考:
计算进程的磁盘IO数据
计算进程的磁盘IO数据主要通过读取 /proc/pid/io 文件的内容来解析, 执行命令后
sudo cat /proc/pid/io
会得到类似以下的输出:
rchar: 2511751
wchar: 115513
syscr: 18106
syscw: 2864
read_bytes: 0
write_bytes: 0
cancelled_write_bytes: 0
我们只用注意 rchar 和 wchar这两个值, rchar代表进程的写入字符数、wchar代表进程读取字符数,磁盘IO就很容计算:
readKbs = (currentReadChar - prevReadChar) / 2 / 1000
writeKbs = (currentWriteChar - prevWriteChar) / 2 / 1000
具体的代码实现:
bool getProcPidIO(int pid, ProcPidIO &io )
ss && "/proc/" && pid && "/io";
std::ifstream ifs( ss.str().c_str() );
if ( ifs.good() ) {
while ( ifs.good() && !ifs.eof() ) {
getline( ifs, s );
if ( sscanf( s.c_str(), "rchar: %lu", &t ) == 1 ) io.rchar =
else if ( sscanf( s.c_str(), "wchar: %lu", &t ) == 1 ) io.wchar =
else if ( sscanf( s.c_str(), "syscr: %lu", &t ) == 1 ) io.syscr =
else if ( sscanf( s.c_str(), "syscw: %lu", &t ) == 1 ) io.syscw =
else if ( sscanf( s.c_str(), "read_bytes: %lu", &t ) == 1 ) io.read_bytes =
else if ( sscanf( s.c_str(), "write_bytes: %lu", &t ) == 1 ) io.write_bytes =
else if ( sscanf( s.c_str(), "cancelled_write_bytes: %lu", &t ) == 1 ) io.cancelled_write_bytes =
DiskStatus StatusMonitor::getProcessDiskStatus(int pid)
ProcPidIO pidIO;
getProcPidIO(pid, pidIO);
DiskStatus status = {0, 0};
if (processWriteKbs-&contains(pid)) {
status.writeKbs = (pidIO.wchar - processWriteKbs-&value(pid)) / (updateDuration / 1000.0);
(*processWriteKbs)[pid] = pidIO.
if (processReadKbs-&contains(pid)) {
status.readKbs = (pidIO.rchar - processReadKbs-&value(pid)) / (updateDuration / 1000.0);
(*processReadKbs)[pid] = pidIO.
计算进程的网络IO数据
计算每个进程的网络IO数据比较复杂,原理步骤如下:
1、获取进程的所有TCP链接的inode, /proc/pid/fd 目录下代表当前进程所有打开的文件描述符,我们举例网易云音乐的进程,内容类似:
andy@andy-PC:~/deepin-system-monitor/build$ ls -al /proc/22269/fd
dr-x------ 2 andy andy
22 17:18 .
dr-xr-xr-x 9 andy andy
22 17:11 ..
lr-x------ 1 andy andy 64 7月
22 17:18 0 -& pipe:[139620]
l-wx------ 1 andy andy 64 7月
22 17:18 1 -& /dev/null
lrwx------ 1 andy andy 64 7月
22 17:18 10 -& socket:[141559]
lrwx------ 1 andy andy 64 7月
22 17:21 100 -& socket:[564075]
lrwx------ 1 andy andy 64 7月
22 17:18 101 -& /dev/shm/.org.chromium.Chromium.NLubPR (deleted)
l-wx------ 1 andy andy 64 7月
22 17:32 102 -& /home/andy/.cache/netease-cloud-music/AlbumCover/4ecaf266bfe8ff6acd7634.tmp (deleted)
l-wx------ 1 andy andy 64 7月
22 17:32 103 -& /home/andy/.cache/netease-cloud-music/CachedSongs/-7c00bba57b7a737c827d.mp3.tmp (deleted)
lrwx------ 1 andy andy 64 7月
22 17:32 104 -& socket:[751267]
lrwx------ 1 andy andy 64 7月
22 17:18 105 -& socket:[751268]
lrwx------ 1 andy andy 64 7月
22 17:21 106 -& socket:[756879]
lrwx------ 1 andy andy 64 7月
22 17:18 11 -& socket:[141560]
lrwx------ 1 andy andy 64 7月
22 17:18 110 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 111 -& /dev/shm/.org.chromium.Chromium.8IQyY6 (deleted)
lrwx------ 1 andy andy 64 7月
22 17:18 112 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/Local Storage/orpheus_orpheus_0.localstorage
lrwx------ 1 andy andy 64 7月
22 17:24 115 -& socket:[753243]
lrwx------ 1 andy andy 64 7月
22 17:18 116 -& socket:[753244]
lr-x------ 1 andy andy 64 7月
22 17:18 117 -& pipe:[753245]
lrwx------ 1 andy andy 64 7月
22 17:18 118 -& anon_inode:[eventfd]
l-wx------ 1 andy andy 64 7月
22 17:21 119 -& pipe:[753245]
lrwx------ 1 andy andy 64 7月
22 17:18 12 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 120 -& socket:[753248]
lrwx------ 1 andy andy 64 7月
22 17:18 121 -& anon_inode:[eventfd]
lr-x------ 1 andy andy 64 7月
22 17:18 122 -& /dev/urandom
lrwx------ 1 andy andy 64 7月
22 17:18 123 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 13 -& anon_inode:[eventfd]
lr-x------ 1 andy andy 64 7月
22 17:18 14 -& anon_inode:inotify
lrwx------ 1 andy andy 64 7月
22 17:18 15 -& socket:[143624]
lr-x------ 1 andy andy 64 7月
22 17:18 16 -& /usr/lib/netease-cloud-music/icudtl.dat
lr-x------ 1 andy andy 64 7月
22 17:18 17 -& /usr/lib/netease-cloud-music/snapshot_blob.bin
lr-x------ 1 andy andy 64 7月
22 17:18 18 -& /usr/lib/netease-cloud-music/natives_blob.bin
lr-x------ 1 andy andy 64 7月
22 17:18 19 -& /usr/lib/netease-cloud-music/locales/zh-CN.pak
l-wx------ 1 andy andy 64 7月
22 17:18 2 -& /dev/null
lr-x------ 1 andy andy 64 7月
22 17:18 20 -& /usr/lib/netease-cloud-music/cef.pak
lr-x------ 1 andy andy 64 7月
22 17:18 21 -& /usr/lib/netease-cloud-music/cef_100_percent.pak
lr-x------ 1 andy andy 64 7月
22 17:18 22 -& /usr/lib/netease-cloud-music/cef_200_percent.pak
lr-x------ 1 andy andy 64 7月
22 17:18 23 -& anon_inode:inotify
lr-x------ 1 andy andy 64 7月
22 17:18 24 -& /usr/lib/netease-cloud-music/cef_extensions.pak
lrwx------ 1 andy andy 64 7月
22 17:18 25 -& socket:[141561]
lrwx------ 1 andy andy 64 7月
22 17:18 26 -& socket:[141562]
lr-x------ 1 andy andy 64 7月
22 17:18 27 -& pipe:[141563]
l-wx------ 1 andy andy 64 7月
22 17:18 28 -& pipe:[141563]
lrwx------ 1 andy andy 64 7月
22 17:18 29 -& socket:[141564]
lrwx------ 1 andy andy 64 7月
22 17:18 3 -& socket:[141558]
lrwx------ 1 andy andy 64 7月
22 17:18 30 -& socket:[141605]
lr-x------ 1 andy andy 64 7月
22 17:18 31 -& pipe:[140610]
l-wx------ 1 andy andy 64 7月
22 17:18 32 -& pipe:[140610]
lrwx------ 1 andy andy 64 7月
22 17:18 33 -& anon_inode:[eventpoll]
lrwx------ 1 andy andy 64 7月
22 17:18 34 -& socket:[137178]
lrwx------ 1 andy andy 64 7月
22 17:18 35 -& socket:[137179]
lr-x------ 1 andy andy 64 7月
22 17:18 36 -& pipe:[137180]
l-wx------ 1 andy andy 64 7月
22 17:18 37 -& pipe:[137180]
lrwx------ 1 andy andy 64 7月
22 17:18 38 -& socket:[137181]
lr-x------ 1 andy andy 64 7月
22 17:18 39 -& anon_inode:inotify
lrwx------ 1 andy andy 64 7月
22 17:18 4 -& anon_inode:[eventfd]
lr-x------ 1 andy andy 64 7月
22 17:18 40 -& pipe:[137189]
l-wx------ 1 andy andy 64 7月
22 17:18 41 -& pipe:[137189]
lrwx------ 1 andy andy 64 7月
22 17:18 42 -& anon_inode:[eventpoll]
lrwx------ 1 andy andy 64 7月
22 17:18 43 -& socket:[137190]
lrwx------ 1 andy andy 64 7月
22 17:18 44 -& socket:[137191]
lr-x------ 1 andy andy 64 7月
22 17:18 45 -& pipe:[137192]
l-wx------ 1 andy andy 64 7月
22 17:18 46 -& pipe:[137192]
lrwx------ 1 andy andy 64 7月
22 17:18 47 -& anon_inode:[eventpoll]
lrwx------ 1 andy andy 64 7月
22 17:18 48 -& anon_inode:[eventpoll]
lrwx------ 1 andy andy 64 7月
22 17:18 49 -& socket:[131820]
lrwx------ 1 andy andy 64 7月
22 17:18 5 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 50 -& socket:[131821]
lrwx------ 1 andy andy 64 7月
22 17:18 51 -& socket:[137193]
lrwx------ 1 andy andy 64 7月
22 17:18 52 -& socket:[137194]
lr-x------ 1 andy andy 64 7月
22 17:18 53 -& pipe:[137195]
l-wx------ 1 andy andy 64 7月
22 17:18 54 -& pipe:[137195]
lr-x------ 1 andy andy 64 7月
22 17:18 55 -& pipe:[131822]
l-wx------ 1 andy andy 64 7月
22 17:18 56 -& pipe:[131822]
lr-x------ 1 andy andy 64 7月
22 17:18 57 -& pipe:[140611]
l-wx------ 1 andy andy 64 7月
22 17:18 58 -& pipe:[140611]
lrwx------ 1 andy andy 64 7月
22 17:18 59 -& socket:[140614]
lrwx------ 1 andy andy 64 7月
22 17:18 6 -& socket:[138694]
lrwx------ 1 andy andy 64 7月
22 17:18 60 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 61 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 62 -& socket:[137196]
lr-x------ 1 andy andy 64 7月
22 17:18 63 -& /dev/urandom
lrwx------ 1 andy andy 64 7月
22 17:18 64 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 65 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/Visited Links
lrwx------ 1 andy andy 64 7月
22 17:18 66 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/Cookies
l-wx------ 1 andy andy 64 7月
22 17:18 67 -& /home/andy/.cache/netease-cloud-music/Logs/webview.log
l-wx------ 1 andy andy 64 7月
22 17:18 68 -& /home/andy/.cache/netease-cloud-music/Logs/web-statis.log
lrwx------ 1 andy andy 64 7月
22 17:18 69 -& socket:[143663]
lr-x------ 1 andy andy 64 7月
22 17:18 7 -& anon_inode:inotify
lrwx------ 1 andy andy 64 7月
22 17:18 70 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 71 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 72 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 73 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 74 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 75 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 76 -& /home/andy/.pki/nssdb/cert9.db
lrwx------ 1 andy andy 64 7月
22 17:18 77 -& /home/andy/.pki/nssdb/key4.db
lrwx------ 1 andy andy 64 7月
22 17:18 78 -& /home/andy/.config/netease-cloud-music/OfflineLibrary.db
lr-x------ 1 andy andy 64 7月
22 17:18 79 -& anon_inode:inotify
lrwx------ 1 andy andy 64 7月
22 17:18 8 -& anon_inode:[eventfd]
lrwx------ 1 andy andy 64 7月
22 17:18 80 -& /home/andy/.config/netease-cloud-music/OfflineLibrary.db
lrwx------ 1 andy andy 64 7月
22 17:18 81 -& socket:[141607]
lrwx------ 1 andy andy 64 7月
22 17:18 82 -& socket:[141608]
lr-x------ 1 andy andy 64 7月
22 17:18 83 -& anon_inode:inotify
lrwx------ 1 andy andy 64 7月
22 17:18 84 -& /home/andy/.config/netease-cloud-music/OnlineLibrary.db
lrwx------ 1 andy andy 64 7月
22 17:18 85 -& /dev/dri/card1
lrwx------ 1 andy andy 64 7月
22 17:18 86 -& socket:[140638]
lrwx------ 1 andy andy 64 7月
22 17:18 87 -& socket:[754448]
lrwx------ 1 andy andy 64 7月
22 17:18 88 -& socket:[140640]
lrwx------ 1 andy andy 64 7月
22 17:18 89 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/index
lrwx------ 1 andy andy 64 7月
22 17:18 9 -& socket:[143622]
lr-x------ 1 andy andy 64 7月
22 17:18 90 -& /dev/shm/.org.chromium.Chromium.hjPeWY (deleted)
lrwx------ 1 andy andy 64 7月
22 17:18 91 -& /dev/shm/.org.chromium.Chromium.hjPeWY (deleted)
lrwx------ 1 andy andy 64 7月
22 17:18 92 -& /dev/shm/.org.chromium.Chromium.gSxJ28 (deleted)
lrwx------ 1 andy andy 64 7月
22 17:18 93 -& /dev/shm/.org.chromium.Chromium.zxWAqZ (deleted)
lrwx------ 1 andy andy 64 7月
22 17:18 94 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/data_0
lrwx------ 1 andy andy 64 7月
22 17:18 95 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/data_1
lrwx------ 1 andy andy 64 7月
22 17:18 96 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/data_2
lrwx------ 1 andy andy 64 7月
22 17:18 97 -& /home/andy/.cache/netease-cloud-music/Cef/Cache/data_3
lr-x------ 1 andy andy 64 7月
22 17:21 98 -& /home/andy/.cache/netease-cloud-music/Logs/web-statis-tmp.log.zip
lrwx------ 1 andy andy 64 7月
22 17:18 99 -& anon_inode:[eventfd]
注意那些以 socket:[number] 的文件描述符, 这些socket开头的文件描述符就对应一个 TCP 链接,后面的数字就代表链接对应的 TCP inode。
2、列出系统中 TCP inode 对应的链接信息,通过命令
cat /proc/net/tcp
可以得到当前 TCP inode 对应的链接信息列表,内容类似:
local_address rem_address
st tx_queue rx_queue tr tm-&when retrnsmt
timeout inode
0: B 0 0A 00
0 25701 1 ffff89bc 100 0 0 10 0
1: 77 0 0A 00
0 21108 1 ffff89bc2d91e7c0 100 0 0 10 0
2: 38 0 0A 00
ffff89bb9e 0 0 10 0
3: BD 0 0A 00
0 25700 1 ffff89bc 0 0 10 0
4: DEC7A8C0:9E7E AFFD 01 00
ffff89bb9e 4 9 10 12
5: 38 0100007F:D934 01 00
ffff89ba 4 4 10 -1
6: DEC7A8C0:D9A0 06C7FCDF:00 02:0
ffff89bb5aced7c0 22 4 29 10 -1
7: DEC7A8C0:9E82 AFFD 01 00
ffff89ba0fa4f7c0 57 4 32 18 13
8: DEC7A8C0:B9B8 7DFD1EC0:01BB 01 00
ffff89ba989fa800 58 4 25 10 -1
9: 0100007F:D938 38 01 006AA 00
ffff89ba 4 30 10 -1
10: DEC7A8C0:A9D6 0 01 63C60 00:0
ffff89bbb8d 0 10 -1
11: DEC7A8C0:CAF0 3CBB 01 00
ffff89bb7c5fd800 72 4 30 10 -1
12: DEC7A8C0:CFC6 DADCDF36:01BB 01 00EB7 00
ffff89bb071aa040 22 4 28 10 -1
13: 38 0100007F:D938 01 00
ffff89ba 4 20 10 -1
14: 0100007F:D934 38 01 002F2 00
ffff89bb6d 4 11 10 -1
15: DEC7A8C0:E168 5D39C834:01BB 01 005E2 00
ffff89bbb8d0f780 57 4 30 10 -1
16: DEC7A8C0:D898 C5A06F3B:01 02:0
ffff89ba989fa080 22 4 24 10 -1
17: DEC7A8C0:93B2 5BF92 01 00
ffff89bb 4 28 10 -1
3、使用 libcap 抓包的方法,计算出每个TCP链接对应的网络流量后,然后反向通过步骤一的 pid &-& inode list 信息,最后计算出每个进程的网络流量。
这么绕的计算方法,我觉得这个世间早以有牛人实现了,Google了一下,发现可以直接使用 libnethogs 这个库来计算每个进程的网络流量。
具体的代码实现可以参考:
nethogs这种方式只能计算出TCP链接的网络流量,无法计算UDP链接的网络流量,当然TCP流量分析已经满足了大部分应用的需求。
Wine程序的网络流量
上面说的方法适用于Linux原生应用的网络进城监控,但是无法直接通过监听Wine程序的网络流量,比如基于Wine运行的迅雷。
当一个Wine程序需要进行网络上传和下载的时候, Wine会后台分配一个 wineserver.real 的进程来完成Wine程序网络代理的功能,wineserver.real 获得网络数据以后再传递给 Wine 程序。
所以计算Wine程序的网络流量的步骤是:
1、统计所有Wine程序运行时的环境变量,通过 GIO_LAUNCHED_DESKTOP_FILE 这个环境变量获得 Wine 程序的 desktop 文件路径;
2、统计所有 wineserver.real 进程的环境变量,通过 GIO_LAUNCHED_DESKTOP_FILE 这个环境变量获得wineserver.real 进程 的 desktop 文件路径;
3、分析系统的TCP链接后,找到匹配的 wineserver.real 的
4、通过 wineserver.real 匹配的 desktop 文件找到对应的 Wine 程序的
5、最后,用 wineserver.real 进程的网络流量数据替换 Wine 程序的网络流量,并清空 wineserver.real 进程的网络流量;
这样用户就可以在系统监视器看到Wine程序的网络流量了,如下图所示:
深度截图_选择区域_57.png
代码参考实现:
std::string getDesktopFileFromName(int pid, QString procName, QString cmdline)
if (desktopfileMaps.contains(cmdline)) {
return desktopfileMaps[cmdline].toStdString();
// Need found desktop file from process environment, if process is wine program.
if (cmdline.startsWith("c:\\")) {
QString gioDesktopFile = Utils::getProcessEnvironmentVariable(pid, "GIO_LAUNCHED_DESKTOP_FILE");
return gioDesktopFile.toStdString();
QDirIterator dir("/usr/share/applications", QDirIterator::Subdirectories);
std::string desktopF
// Convert to lower characters.
QString procname = procName.toLower();
// Replace "_" instead "-", avoid some applications desktop file can't found, such as, sublime text.
procname.replace("_", "-");
// Concat desktop file.
QString processFilename = procname + ".desktop";
if (GUI_BLACKLIST_MAP.find(procname) == GUI_BLACKLIST_MAP.end()) {
while(dir.hasNext()) {
if (dir.fileInfo().suffix() == "desktop") {
if (dir.fileName().toLower().contains(processFilename)) {
desktopFile = dir.filePath().toStdString();
dir.next();
return desktopF
wineApplicationDesktopMaps-&clear();
wineServerDesktopMaps-&clear();
for (auto &i:processes) {
int pid = (&i.second)-&
QString cmdline = Utils::getProcessCmdline(pid);
bool isWineProcess = cmdline.startsWith("c:\\");
QString name = getProcessName(&i.second, cmdline);
QString user = (&i.second)-&
double cpu = (*processCpuPercents)[pid];
std::string desktopFile = getDesktopFileFromName(pid, name, cmdline);
QString title = findWindowTitle-&getWindowTitle(pid);
bool isGui = (title != "");
// Record wine application and wineserver.real desktop file.
// We need transfer wineserver.real network traffic to the corresponding wine program.
if (name == "wineserver.real") {
// Insert pid&-&desktopFile to map to search in all network process list.
QString gioDesktopFile = Utils::getProcessEnvironmentVariable(pid, "GIO_LAUNCHED_DESKTOP_FILE");
if (gioDesktopFile != "") {
(*wineServerDesktopMaps)[pid] = gioDesktopF
// Insert desktopFile&-&pid to map to search in all network process list.
// If title is empty, it's just a wine program, but not wine GUI window.
if (isWineProcess && title != "") {
(*wineApplicationDesktopMaps)[QString::fromStdString(desktopFile)] =
if (isGui) {
guiProcessNumber++;
systemProcessNumber++;
bool appendItem =
if (filterType == OnlyGUI) {
appendItem = (user == currentUsername && isGui);
} else if (filterType == OnlyMe) {
appendItem = (user == currentUsername);
} else if (filterType == AllProcess) {
appendItem =
if (appendItem) {
if (title == "") {
if (isWineProcess) {
// If wine process's window title is blank, it's not GUI window process.
// Title use process name instead.
title = getDisplayNameFromName(name, desktopFile);
QString displayN
if (filterType == AllProcess) {
displayName = QString("[%1] %2").arg(user).arg(title);
displayName =
long memory = ((&i.second)-&resident - (&i.second)-&share) * sysconf(_SC_PAGESIZE);
if (desktopFile.size() == 0) {
icon = findWindowTitle-&getWindowIcon(findWindowTitle-&getWindow(pid), 24);
icon = getDesktopFileIcon(desktopFile, 24);
ProcessItem *item = new ProcessItem(icon, name, displayName, cpu, memory, pid, user, (&i.second)-&state);
// Fill GUI processes information for continue merge action.
if (filterType == OnlyGUI) {
if (childInfoMap.contains(pid)) {
long memory = ((&i.second)-&resident - (&i.second)-&share) * sysconf(_SC_PAGESIZE);
childInfoMap[pid].cpu =
childInfoMap[pid].memory =
// Transfer wineserver.real network traffic to the corresponding wine program.
QMap&int, NetworkStatus&::
for (i = networkStatusSnapshot.begin(); i != networkStatusSnapshot.end(); ++i) {
if (wineServerDesktopMaps-&contains(i.key())) {
QString wineDesktopFile = (*wineServerDesktopMaps)[i.key()];
if (wineApplicationDesktopMaps-&contains(wineDesktopFile)) {
// Transfer wineserver.real network traffic to the corresponding wine program.
int wineApplicationPid = (*wineApplicationDesktopMaps)[wineDesktopFile];
networkStatusSnapshot[wineApplicationPid] = networkStatusSnapshot[i.key()];
// Reset wineserver network status to zero.
NetworkStatus networkStatus = {0, 0, 0, 0};
networkStatusSnapshot[i.key()] = networkS
找到进程对应的名字
主要的名字主要有三种形式:图形窗口的标题、Desktop文件对应的本地化名称和最后的命令行名称。
图形窗口的标题的步骤是:
1、通过XCB分析 _NET_CLIENT_LIST_STACKING 数据列出所有图形窗口的XID
2、通过XCB分析 _NET_WM_PID 得出每个窗口对应的 pid
3、然后对比图形窗口的 pid list 和 process pid list, 找到所有图形窗口的 pid list
4、最后通过XCB分析 xid 对应的 _NET_WM_NAME 来查找图形窗口的标题
具体的代码实现参考:
QList&xcb_window_t& WindowManager::getWindows()
QList&xcb_window_t&
xcb_get_property_reply_t *listReply = getProperty(rootWindow, "_NET_CLIENT_LIST_STACKING", XCB_ATOM_WINDOW);
if (listReply) {
xcb_window_t *windowList = static_cast&xcb_window_t*&(xcb_get_property_value(listReply));
int windowListLength = listReply-&
for (int i = 0; i & windowListL i++) {
xcb_window_t window = windowList[i];
foreach(QString type, getWindowTypes(window)) {
if (type == "_NET_WM_WINDOW_TYPE_NORMAL" ||
type == "_NET_WM_WINDOW_TYPE_DIALOG"
bool needAppend =
QStringList states = getWindowStates(window);
if (states.length() == 0 ||
(!states.contains("_NET_WM_STATE_HIDDEN"))) {
if (getWindowWorkspace(window) == getCurrentWorkspace(rootWindow)) {
needAppend =
if (needAppend) {
windows.append(window);
free(listReply);
// We need re-sort windows list from up to bottom,
// to make compare cursor with window area from up to bottom.
std::reverse(windows.begin(), windows.end());
// Add desktop window.
windows.append(rootWindow);
// Just use for debug.
// foreach (auto window, windows) {
qDebug() && getWindowName(window);
int WindowManager::getWindowPid(xcb_window_t window)
xcb_get_property_reply_t *reply = getProperty(window, "_NET_WM_PID", XCB_ATOM_CARDINAL);
int pid = 0;
if (reply) {
pid = *((int *) xcb_get_property_value(reply));
free(reply);
QString WindowManager::getWindowName(xcb_window_t window)
if (window == rootWindow) {
return tr("Desktop");
xcb_get_property_reply_t *reply = getProperty(window, "_NET_WM_NAME", getAtom("UTF8_STRING"));
if (reply) {
QString result = QString::fromUtf8(static_cast&char*&(xcb_get_property_value(reply)), xcb_get_property_value_length(reply));
free(reply);
return QString();
得到Desktop对应的名称原理:
1、通过读取 /proc/pid/cmdline 得到进程对应的启动命令行
2、提取 cmdline 第一个参数得到启动命令
3、通过启动命令在 /usr/share/applications 目录下查找对应的 *.desktop 文件
4、分析文件的 Name[locale] 字符串,得到本地化的名字, locale 在中文表示 zh_CN
具体的代码实现参考:
QString getProcessCmdline(pid_t pid)
fs.open("/proc/"+std::to_string((long)pid)+"/cmdline", std::fstream::in);
std::getline(fs,temp);
fs.close();
} catch(std::ifstream::failure e) {
return "FAILED TO READ PROC";
// change \0 to ' '
std::replace(temp.begin(),temp.end(),'\0',' ');
if (temp.size()&1) {
return "";
return QString::fromStdString(temp).trimmed();
QString getProcessNameFromCmdLine(const pid_t pid)
std::string cmdline = getProcessCmdline(pid).toStdString();
if (cmdline.size()&1) {
return "";
// Maintain linux paths.
std::replace(cmdline.begin(),cmdline.end(),'\\','/');
// Get cmdline arguments and first argument name.
auto args = explode(cmdline, ' ');
QString name = QFileInfo(QString::fromStdString(args[0])).fileName();
// Get first argument that start with '/' if first argument is script program, such as 'python'.
auto pos = SCRIPT_PROGRAM_MAP.find(name);
if (pos != SCRIPT_PROGRAM_MAP.end() && args.size() & 1) {
for (unsigned int i = 1; i & args.size(); i++) {
QString argument = QString::fromStdString(args[i]);
// Return first argument that start with '/'.
if (argument.startsWith("/")) {
return QFileInfo(argument).fileName();
for (unsigned int j = 1; j & args.size(); j++) {
QString argument = QString::fromStdString(args[j]);
// Return first argument that not start with '-'.
if (!argument.startsWith("-")) {
return QFileInfo(argument).fileName();
QString getDisplayNameFromName(QString procName, std::string desktopFile, bool displayProcessName)
QString procname = procName.toLower();
if (processDescriptions.contains(procname)) {
if (displayProcessName) {
return QString("%1
( %2 )").arg(processDescriptions[procname], procName);
return processDescriptions[procname];
if (desktopFile.size() == 0) {
return procN
in.open(desktopFile);
QString displayName = procN
while(!in.eof()) {
std::getline(in,line);
QString lineContent = QString::fromStdString(line);
QString localNameFlag = QString("Name[%1]=").arg(QLocale::system().name());
QString nameFlag = "Name=";
QString genericNameFlag = QString("GenericName[%1]=").arg(QLocale::system().name());
if (lineContent.startsWith(localNameFlag)) {
displayName = lineContent.remove(0, localNameFlag.size());
} else if (lineContent.startsWith(genericNameFlag)) {
displayName = lineContent.remove(0, genericNameFlag.size());
} else if (lineContent.startsWith(nameFlag)) {
displayName = lineContent.remove(0, nameFlag.size());
in.close();
return displayN
第三种进程名的方式已经在函数 getProcessNameFromCmdLine 的代码实现中体现了。
找到进程二进制文件所在位置
进程管理中除了查看进程的状态,对进程进行简单的结束/暂停管理操作以外,最重要的附加功能就是,我们要知道这个软件到底是哪个命令启动的,这个命令所在的目录,这样对于我们彻底了解进程背后的软件非常有帮助。
深度系统监视器实现了一个 ”查找命令所在位置“ 的右键功能,这个功能的实现分为两种情况:
1、Linux原生应用进程
2、Wine进程
Linux原生应用进程查找二进制的步骤:
1、读取 /proc/pid/cmdline 得到命令行参数
2、获取 cmdline 第一个参数,即命令行路径
3、通过 which 命令来查询命令行的绝对路径
Wine进程查找二进制的步骤:
1、读取 /proc/pid/cmdline 得到命令行参数,一般是 c:\xxxxxxx\xxxx.exe 的Windows路径
2、转换 Windows 路径为: drive_c/xxxxxxx/xxx.exe 的Linux相对路径
3、通过读取 /proc/pid/environ 路径,找到进程的环境变量列表
4、进一步找到 WINEPREFIX 对应的值,一般是 ~/.deepinwine/xxx 的软件安装目录形式
5、最后链接软件安装目录+相对路径的形式,得到Wine进程启动命令的绝对路径,一般是 ~/.deepinwine/xxx/drive_c/xxx/xxx.exe的形式
具体代码参考实现:
void ProcessManager::openProcessDirectory()
for (int pid : *actionPids) {
QString cmdline = Utils::getProcessCmdline(pid);
if (cmdline.size() & 0) {
// Found wine program location if cmdline starts with c://.
if (cmdline.startsWith("c:\\")) {
QString winePrefix = Utils::getProcessEnvironmentVariable(pid, "WINEPREFIX");
cmdline = cmdline.replace("\\", "/").replace("c:/", "/drive_c/");
DDesktopServices::showFileItem(winePrefix + cmdline);
// Else find program location through 'which' command.
cmdline = cmdline.split(QRegExp("\\s")).at(0);
QProcess whichP
QString exec = "which";
whichProcess.start(exec, params);
whichProcess.waitForFinished();
QString output(whichProcess.readAllStandardOutput());
QString processPath = output.split("\n")[0];
DDesktopServices::showFileItem(processPath);
actionPids-&clear();
QString getProcessEnvironmentVariable(pid_t pid, QString environmentName)
fs.open("/proc/"+std::to_string((long)pid)+"/environ", std::fstream::in);
std::getline(fs,temp);
fs.close();
} catch(std::ifstream::failure e) {
return "FAILED TO READ PROC";
// change \0 to ' '
std::replace(temp.begin(),temp.end(),'\0','\n');
if (temp.size()&1) {
return "";
foreach (auto environmentVariable, QString::fromStdString(temp).trimmed().split("\n")) {
if (environmentVariable.startsWith(environmentName)) {
return environmentVariable.remove(0, QString("%1=").arg(environmentName).length());
return "";
用setcap替换setuid的方式给予读取系统目录的权限
上面讲解了深度系统监视器的核心模块的原理和代码参考实现,我们会发现大部分都要读取系统目录 /proc, /proc这个目录的大部分内容只有root用户才有权限读取。
很多初学者喜欢用setuid的方式直接赋予二进制root权限,但是这样非常危险,会造成图形前端获得过大的权限,从而产生安全漏洞。
Linux内核针对这种情况有更好的实现方式,用 setcap 给予二进制特定的权限,保证二进制的特殊权限在最小的范围中,比如在深度系统监视器中就用命令:
sudo setcap cap_kill,cap_net_raw,cap_dac_read_search,cap_sys_ptrace+ep ./deepin-system-monitor
来给予进程相应的能力,比如:
cap_net_raw 对应网络文件读取权限
cap_dac_read_search 对应文件读取检查权限
cap_sys_ptrace 对应进程内存信息读取权限
这样,在保证二进制有对应读取权限的同时,又保证了二进制最小化的权限范围,最大化的保证了应用和系统的安全。
最后,深度系统监视器整个项目都遵守GPLv3许可证协议,欢迎各位大神贡献代码:
Deepin操作系统联合创始人,开源软件开发者。
linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大家期待吧 命令区 系统管理与维护命令 date date(选项)(参数)|
说明 || :-------- | --------:||...
Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意义的,您不是第一个为此困惑的人,当然,也不会是最后一个:)大多数的美国人读 ubuntu 时,将 u 作为元音发音,类似单词 who 或者 boo ,重音在第二...
如果你想知道你的服务器正在做干什么,你就需要了解一些基本的命令,一旦你精通了这些命令,那你就是一个专业的 Linux 系统管理员。 监控命令## iostat### iostat命令用来显示存储系统的详细信息,通常用它来监控磁盘 I/O 的情况。要特别注意 iostat 统...
第一章1.设计现代OS的主要目标是什么?答:(1)有效性 (2)方便性 (3)可扩充性 (4)开放性2.OS的作用可表现在哪几个方面?答:(1)OS作为用户与计算机硬件系统之间的接口(2)OS作为计算机系统资源的管理者(3)OS实现了对计算机资源的抽象3.为什么说OS实现了...
本文欢迎转载,转载请注明原文链接,并附作者个人信息李艳鹏。 上一篇文章《Java服务化系统线上应急和技术攻关,你必须拥有的那些应用层脚本和Java虚拟机命令》介绍了笔者在互联网公司里线上应急和技术攻关过程中积累的应用层脚本和Java虚拟机命令,这些脚本和命令在发现问题和定位...
都说一到夜里人们就有许多情绪与感慨,也许是因为在深夜,上班族结束了一天的工作,学生也在忙碌的学习中得到休息和片刻的摆脱,而作为个即将毕业实习的大学狗,没有太多的经历,没有过硬的技能,就只有些闲时里喝的鸡汤文和所谓的成功学外加点把妹套路什么的。。 咳咳还是好好说话吧???,画...
“哐”的一声,他摔门而去。随着他的离去,她的心脏好像被拎起而又被硬生生地摔在地下,碎成了几瓣。她心痛得简直要窒息,眼泪不由自主地夺眶而出…… 她的心一阵阵绞痛,痛得干呕起来,之后,她像一个被抽尽了气的橡皮人,整个瘫在了地上。室内就像是刚结束了一场战斗还未来得及打扫的战场,地...
我们好像去过那儿 你拉着我爬树 拉着我捉蜻蜓 我们的笑绽放成春日的红漾 我们好像去过那儿 你说隔壁班的姑娘 是你一百分的女孩 偷偷写的情书被折成了纸飞机 我们好像去过那儿 你站在山顶 向风宣誓你会完成的梦想 那时的情怀和当年 那萧瑟季节里未结果的爱 变成舞台上 最凄美的谢幕...
昨天单位开一季度总结会,全体员工到场,不准请假,毕竟是大BOSS的首秀,新官上任三把火,要求严格在所难免,公司260人,除去值班人员,到场230人,这着实不容易,虽然在同一个单位,有些跑业务的老员工竟然不认识,平时见面非常难,这也算是难得的机会。 会议的内容无外乎两点: 1...
我们时常见到一些男生吐槽说,他女朋友太矫情了,然后第二天照常秀恩爱,发狗粮。那么就有很多人不理解了,男生为什么会喜欢那些矫情的女生呢? 其实之所以很多男生会喜欢矫情的女生,理由很简单: 因为她们的情绪容易掌控。 矫情的女生会更容易在语言交流和社交软件中透露自己的需要,会更坦...

我要回帖

更多关于 深度系统一键装机 的文章

 

随机推荐