副标题: 第2版
作者: W.Richard Stevens / Stephen A.Rago
译者: 尤晋元 / 张亚英 / 戚正伟
出版社: 人民邮电出版社
出版年: 2006年
页数: 780页
定价: 99.00元
装帧: 平装
ISBN: 9787115147318
作者: W.Richard Stevens / Stephen A.Rago
译者: 尤晋元 / 张亚英 / 戚正伟
出版社: 人民邮电出版社
出版年: 2006年
页数: 780页
定价: 99.00元
装帧: 平装
ISBN: 9787115147318
内容简介 · · · · · ·
本书是被誉为UNIX编程“圣经”的Advanced Programming in the UNIX Environment一书的更新版。在本书第1版出版后的十几年中,UNIX行业已经有了巨大的变化,特别是影响UNIX编程接口的有关标准变化很大。本书在保持了前一版风格的基础上,根据最新的标准对内容进行了修订和增补,反映了最新的技术发展。书中除了介绍UNIX文件和目录、标准I/O库、系统数据文件和信息、进程环境、进程控制、进程关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在此基础上介绍了多个应用示例,包括如何创建数据库函数库以及如何与网络打印机通信等。此外,还在附录中给出了函数原型和部分习题的答案。
本书内容权威,概念清晰,阐述精辟,对于所有层次UNIX程序员都是一本不可或缺的参考书。
本书内容权威,概念清晰,阐述精辟,对于所有层次UNIX程序员都是一本不可或缺的参考书。
作者简介 · · · · · ·
作者:(美)史蒂文斯 (美)拉戈 译者:尤晋元 张亚英 戚正伟
W.Richard Stevens,备受赞誉的技术作家,生前著有多种经典的传世之作,包括《UNIX网络编程》(两卷本)、《TCP/IP详解》(三卷本)和本书第1版。 尤晋元,上海交通大学计算机科学及工程系教授、博士生导师。在科研方面,主要从事操作系统和分布对象计算技术方面的研究;在教学方面,长期承担操作系统及分布计算等课程的教学工作。主编和翻译了多本操作系统教材和参考书,包括《UNIX操作系统教程》、《UNIX高级编程技术》、《UNIX环境高级编程》和《操作系统:设计与实现》等。
W.Richard Stevens,备受赞誉的技术作家,生前著有多种经典的传世之作,包括《UNIX网络编程》(两卷本)、《TCP/IP详解》(三卷本)和本书第1版。 尤晋元,上海交通大学计算机科学及工程系教授、博士生导师。在科研方面,主要从事操作系统和分布对象计算技术方面的研究;在教学方面,长期承担操作系统及分布计算等课程的教学工作。主编和翻译了多本操作系统教材和参考书,包括《UNIX操作系统教程》、《UNIX高级编程技术》、《UNIX环境高级编程》和《操作系统:设计与实现》等。
豆瓣成员常用的标签(共195个) · · · · · ·
喜欢读"UNIX环境高级编程"的人也喜欢 · · · · · ·
按有用程度 按页码先后 最新笔记
-
第234页
timebug (绝对清晰,是风格上唯一的美。)
文中提到: 大多数UNIX调试程序都使用core文件以检查进程终止时的状态。 如书上表10-1所示,当进程接收到例如SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGSEGV(无效内存引用)等信号的时候会产生相应的core文件,该core文件复制了进程的存储镜像。 在运行程序的时候,我们会经常遇到Segmentation fault,也就是段错误,表示该进程进行了一次无效的内存访问。对于此类情况,我们很难发现问题具体是出现在程序的哪一行,如... (更多)文中提到:
如书上表10-1所示,当进程接收到例如SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGSEGV(无效内存引用)等信号的时候会产生相应的core文件,该core文件复制了进程的存储镜像。在运行程序的时候,我们会经常遇到Segmentation fault,也就是段错误,表示该进程进行了一次无效的内存访问。对于此类情况,我们很难发现问题具体是出现在程序的哪一行,如果是一小段程序,我们可以直接用gdb一步一步跟踪调试,但是如果程序规模很大,这样做显然就不实现了。回过头来,我们发现对于此类错误,程序会接收到SIGSEGV(无效内存引用)信号,而该信号在终止程序的同时,会在当前目录产生一个相应的core文件。因此,我们可以让gdb根据该core文件分析中断的位置,也就是出现该错误的位置。首先,我们应该现查看当前系统是否开启了core文件支持(以GNU/Linux为例):大多数UNIX调试程序都使用core文件以检查进程终止时的状态。
~ $ ulimit -c 0 ~ $ ulimit -c unlimited ~ $ ulimit -c unlimited
0表示未开启,大于0的表示默认core文件的大小,如果超过此大小,则截断,这会造成core文件的信息不完整,因此我们这里将其设置为unlimited,也就是无限大。接下来,我们写一段C代码来测试:#include <stdio.h> char *str; void core_test() { printf("%c\n",*str); } int main(int argc, char *argv[]) { core_test(); return 0; }然后,依次进行编译(无警告无错误),运行(段错误),并结合产生的core文件调试:~ $ gcc -o test test.c -g ~ $ ./test Segmentation fault (core dumped) ~ $ file core core: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './test' ~ $ gdb test core GNU gdb (Gentoo 7.3.1 p1) 7.3.1 Copyright (C) 2011 Free Software Foundation, Inc. ... Core was generated by `./test'. Program terminated with signal 11, Segmentation fault. #0 0x08048574 in core_test () at test.c:7 7 printf("%c\n",*str); (gdb) where #0 0x08048574 in core_test () at test.c:7 #1 0x0804859d in main (argc=1, argv=0xbfed0214) at test.c:12 (gdb) quit很明显,问题是出在这里:#0 0x08048574 in core_test () at test.c:7 7 printf("%c\n",*str);字符指针str未经初始化就试图(解除引用)访问它所指向的内存空间,导致出现无效的内存访问。其中where命令用来查看当前调用栈信息。 (收起)2011-10-30 13:28:33 2人收藏 回应
-
第269页
timebug (绝对清晰,是风格上唯一的美。)
/代码内容已省略/ 关于sigsuspend函数,书中的解释是: 将进程的信号屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。 接下来,书上举了3个例子来说明sigsuspend的作用,但看完前2个之后,却给我留下了不... (更多)#include <signal.h> int sigsuspend(const sigset_t *sigmask);
关于sigsuspend函数,书中的解释是:
接下来,书上举了3个例子来说明sigsuspend的作用,但看完前2个之后,却给我留下了不少疑问,在看第3个的时候,心想不能就这么糊里糊涂地翻过去了,因此求助了google大神,发现网上对于该函数的疑问还真不少,具体表现为对书中前2个例子中该函数的作用感到不解,幸而有不少人给出了比较通俗的解释,我也便在此结合自己的理解做一番整理。既然前2个例子都不是那么直观,那么我们就先来看下相对直观地显示了sigsuspend函数作用的第3个例子(程序清单10-17)吧,但是在说明该函数之前,有必要先来了解一下清单中给出的几个函数的作用,以及它们是如何通过信号实现父、子进程同步的。其中,有这么一个函数:将进程的信号屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。
void WAIT_PARENT(void) { while (sigflag == 0) sigsuspend(&zeromask); /* and wait for parent */ sigflag = 0; /* * Reset signal mask to original value. */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); }该函数的作用不难看出来,是子进程用来等待父进程的,以便使父进程先于子进程运行,等待的过程发生在该函数体内的while循环中,而我们要讨论的sigsuspend函数就在这里面被调用(也就是具体实现了该等待过程),不过暂时先无视它。这里有个问题,子进程不能就这样一直等下去,实际上,在父进程运行完后,父进程会发送一个信号给子进程,具体实现为如下函数:void TELL_CHILD(pid_t pid) { kill(pid, SIGUSR1); /* tell child we're done */ }也就是说,在父进程执行完后,会发送一个SIGUSR1信号给等待它的子进程,用来告诉它,“孩子,现在该你运行了”。书上p187页程序清单8-7中的代码就很好地演示了这一过程:pid_t pid; TELL_WAIT(); if ((pid == fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { WAIT_PARENT(); /* parent goes first */ /* child does something. */ } else { /* parent does something. */ TELL_CHILD(pid); /* tell child we're done */其中的TELL_WAIT()函数,用来在父、子进程同步过程开始之前进行一些必要的初始化工作,回到程序清单10-17,该函数的定义如下:void TELL_WAIT(void) { if (signal(SIGUSR1, sig_usr) == SIG_ERR) err_sys("signal (SIGUSR1) error"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) err_sys("signal (SIGUSR2) error"); sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask, SIGUSR1); sigaddset(&newmask, SIGUSR2); /* * Block SIGUSR1 and SIGUSR2, and save current signal mask. */ if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) err_sys("SIG_BLOCK error"); }[03-06] 用signal函数对SIGUSR1和SIGUSR2两个信号进行注册,这样一来,当进程接收到这两个信号的时候,就会调用相应的信号处理函数,特别地,这里的两信号绑定的信号处理函数同为sig_usr,该函数的功能也很简单,就是将全局静态变量sigflag的值赋为1。[07-16] 首先,初始化zeromask和newmask两信号屏蔽字,接着将SIGUSR1和SIGUSR2信号添加到newmask中,最后将当前信号屏蔽字修改为newmask,并将原先的信号屏蔽字保存到oldmask中。通俗一点说就是,在当前信号集中屏蔽掉了SIGUSR1和SIGUSR2两个信号,如果在这段时间内有这两信号过来的话,进程就将它们阻塞了,直到将它们解除屏蔽。但是为什么在一开始就要屏蔽掉SIGUSR1和SIGUSR2这两信号呢?让我们回到前面的WAIT_PARENT函数,我们已经知道,子进程等待父进程的过程发生在该函数一开始的while循环体内,这里有一点很明确,甚至我们暂时不需要知道该过程具体是怎样实现的,那就是在这过程中子进程会一直等待,直到父进程发送执行完成的信号(SIGUSR1)过来,然后调用相应的信号处理函数(sig_usr)将sigflag设置为1,至此,该过程结束,紧接着是跳出while循环。为了方便说明,我们简单地将此过程描述为x过程:while (sigflag == 0) x_process(); /* and wait for parent */ sigflag = 0;然后,我们考虑这样一个情况,如果之前没有屏蔽掉SIGUSR1信号,那么该信号就会随时被送到子进程中,假设恰好在子进程刚进入while循环体内,也就是在判断完sigflag == 0之后,该信号到达(这里有一个时间窗口,此时x过程尚未发生),并调用信号处理函数,设置sigflag = 1,接着从信号处理程序返回后,才开始执行x过程,如果此后没有任何信号(不一定要SIGUSR1)到达,那么子进程将一直阻塞在x过程中。(SIGUSR2同理)因此,在x过程开始之前,必须屏蔽掉SIGUSR1和SIGUSR2这两信号。但是,刚刚不是说子进程的x过程要等待接收SIGUSR1信号吗?屏蔽掉了不就接收不到了?所以,这就需要x过程执行一个额外的动作,即解除屏蔽。这下,就清楚了x过程具体会发生什么了,对于子进程的x过程,具体执行过程如下:(1) 解除对SIGUSR1信号的屏蔽(2) 等待父进程的SIGUSR1信号(此时子进程被挂起)(3) 接收到SIGUSR1信号,执行相应信号处理函数,sigflag = 1(4) 退出x过程既然我们清楚了x过程的执行步骤,那么为什么这里要选择sigsuspend函数来实现x过程呢?如果换成以下方法来实现x过程会如何?/* reset signal mask, which unblocks SIGUSR1 */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); /* window is open */ pause(); /*wait for signal to occur */我们看到,此方法(1)先解除信号(SIGUSR1)屏蔽,(2)然后用pause()函数等待父进程的SIGUSR1信号(子进程被挂起),(3)(4)与前面一样。这里为何要强调一下(1)(2)步骤呢?因为此时,它们是有先后次序的,是两个操作,所以用了‘先’和‘然后’两个词来加以描述。然而,这样的话,在这两个操作之间,就会出现另一个时间窗口(前一个是while循环体和x过程之间),同样如果父进程的SIGUSR1信号此时到达,之后再执行pause()等待,那么子进程就会一直阻塞在这里,除非再有一个信号过来。那么,sigsuspend函数实现x过程就不会出现这样的情况了吗?是的,因为sigsuspend是一个原子操作,所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位。因此,它在实现解除屏蔽和等待之间是没有时间窗口的,这也就避免了上述问题。具体步骤如下:(1) 设置新的mask阻塞当前进程 (在WAIT_PARENT中具体表现为屏蔽SIGUSR1信号)(2) 收到信号,恢复原先mask (解除对SIGUSR1信号的屏蔽)(3) 调用该进程设置的信号处理函数(4) 待信号处理函数返回后,sigsuspend返回这样一来就清楚了吧,那么,接下来书中的前2个例子也就好理解了。当然,至于你信不信,反正我是信了。感谢:(1) http://bit.ly/w0y9PZ (2) http://bit.ly/uv96sQ (3) http://bit.ly/w2NMzV (收起)2011-11-02 08:25:54 1回应
-
第1页
在信号一章,许多的语句需要字句斟酌,一字一字研读,如果某部分有疑问,翻看英文版,多半都能得到解决。这本书的前部分,译者做得很不错,但是,中文毕竟还是翻译过来的,用词的准确性比不上英文原版。 在信号量一章存在着许多的技术细节,中文的翻译,仅仅是语序稍微做调整,或者字面的意思已经完全被翻译出来,但依旧无法准确地表达,翻看原文,便会恍然大悟,再看中文翻译版,你也不会觉得这样的翻译存在瑕疵,翻译不存在问题... (更多)在信号一章,许多的语句需要字句斟酌,一字一字研读,如果某部分有疑问,翻看英文版,多半都能得到解决。这本书的前部分,译者做得很不错,但是,中文毕竟还是翻译过来的,用词的准确性比不上英文原版。在信号量一章存在着许多的技术细节,中文的翻译,仅仅是语序稍微做调整,或者字面的意思已经完全被翻译出来,但依旧无法准确地表达,翻看原文,便会恍然大悟,再看中文翻译版,你也不会觉得这样的翻译存在瑕疵,翻译不存在问题,但就是不如英文原版明了。从一种语言到另外一种语言的转换,仅仅是语序的改变,也可能会造成对某个意思强调的丢失,从而造成影响。 (收起)2011-09-17 23:06:50 回应
-
第147页
mark (毕业论文!!!)
进程环境、操作系统 #include <stdlib.h> exit _Exit #include <unistd.h> _exit exit(0); 等价于 return (0); cc echo $? # 打印终止状态 cc -std=c99 echo $? #include <stdlib.h> int atexit(void(*func)(void)); sysconf exec myexit 命令行参数 argc argv 环境表 extern char** environ getenv putenv C 程序的存储空间布局 ·正文段 ·初始化数据段 ·非初.. (更多)进程环境、操作系统#include <stdlib.h>exit_Exit#include <unistd.h>_exitexit(0);等价于return (0);ccecho $? # 打印终止状态cc -std=c99echo $?#include <stdlib.h>int atexit(void(*func)(void));sysconfexecmyexit命令行参数argc argv环境表extern char** environgetenvputenvC 程序的存储空间布局·正文段·初始化数据段·非初始化数据段·栈·堆典型的存储器安排:(高地址)命令行参数和环境变量---------------------------栈---------------------------堆---------------------------未初始化的数据(由 exec 初始化为 0)---------------------------初始化的数据(由 exec 从程序文件中读取)---------------------------正文(有 exec 从程序文件中读取)(低地址)size 文件名共享库cc -staticls -lsizeccls -lsize存储器分配malloccalloc(初始化)reallocfreesbrk (收起)2011-05-21 11:36:31 回应
-
第234页
timebug (绝对清晰,是风格上唯一的美。)
文中提到: 大多数UNIX调试程序都使用core文件以检查进程终止时的状态。 如书上表10-1所示,当进程接收到例如SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGSEGV(无效内存引用)等信号的时候会产生相应的core文件,该core文件复制了进程的存储镜像。 在运行程序的时候,我们会经常遇到Segmentation fault,也就是段错误,表示该进程进行了一次无效的内存访问。对于此类情况,我们很难发现问题具体是出现在程序的哪一行,如... (更多)文中提到:
如书上表10-1所示,当进程接收到例如SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGSEGV(无效内存引用)等信号的时候会产生相应的core文件,该core文件复制了进程的存储镜像。在运行程序的时候,我们会经常遇到Segmentation fault,也就是段错误,表示该进程进行了一次无效的内存访问。对于此类情况,我们很难发现问题具体是出现在程序的哪一行,如果是一小段程序,我们可以直接用gdb一步一步跟踪调试,但是如果程序规模很大,这样做显然就不实现了。回过头来,我们发现对于此类错误,程序会接收到SIGSEGV(无效内存引用)信号,而该信号在终止程序的同时,会在当前目录产生一个相应的core文件。因此,我们可以让gdb根据该core文件分析中断的位置,也就是出现该错误的位置。首先,我们应该现查看当前系统是否开启了core文件支持(以GNU/Linux为例):大多数UNIX调试程序都使用core文件以检查进程终止时的状态。
~ $ ulimit -c 0 ~ $ ulimit -c unlimited ~ $ ulimit -c unlimited
0表示未开启,大于0的表示默认core文件的大小,如果超过此大小,则截断,这会造成core文件的信息不完整,因此我们这里将其设置为unlimited,也就是无限大。接下来,我们写一段C代码来测试:#include <stdio.h> char *str; void core_test() { printf("%c\n",*str); } int main(int argc, char *argv[]) { core_test(); return 0; }然后,依次进行编译(无警告无错误),运行(段错误),并结合产生的core文件调试:~ $ gcc -o test test.c -g ~ $ ./test Segmentation fault (core dumped) ~ $ file core core: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './test' ~ $ gdb test core GNU gdb (Gentoo 7.3.1 p1) 7.3.1 Copyright (C) 2011 Free Software Foundation, Inc. ... Core was generated by `./test'. Program terminated with signal 11, Segmentation fault. #0 0x08048574 in core_test () at test.c:7 7 printf("%c\n",*str); (gdb) where #0 0x08048574 in core_test () at test.c:7 #1 0x0804859d in main (argc=1, argv=0xbfed0214) at test.c:12 (gdb) quit很明显,问题是出在这里:#0 0x08048574 in core_test () at test.c:7 7 printf("%c\n",*str);字符指针str未经初始化就试图(解除引用)访问它所指向的内存空间,导致出现无效的内存访问。其中where命令用来查看当前调用栈信息。 (收起)2011-10-30 13:28:33 2人收藏 回应
-
第286页
第十章的第七个练习题: 为什么在siginfo结构的si_uid字段中包括实际用户ID而不是有效用户ID? 课后给出的解释是,如果信号由其他用户的进程发出,进程必须是设置用户ID为根(不懂是什么意思)的或者是接受进程的所有者,否则kill不能执行。 而kill的执行要么是超级用户,要么发送者的实际用户ID或者有效用户ID必须等于接收者的实际或者有效用户ID。 对这题的解释无法理解,有谁能帮忙解释一下。 (更多)第十章的第七个练习题:为什么在siginfo结构的si_uid字段中包括实际用户ID而不是有效用户ID?课后给出的解释是,如果信号由其他用户的进程发出,进程必须是设置用户ID为根(不懂是什么意思)的或者是接受进程的所有者,否则kill不能执行。而kill的执行要么是超级用户,要么发送者的实际用户ID或者有效用户ID必须等于接收者的实际或者有效用户ID。对这题的解释无法理解,有谁能帮忙解释一下。 (收起)2012-01-04 19:20:42 回应
书评 · · · · · · (共28条) 我来评论这本书
热门评论 最新评论
不仅仅是编程
-
- sandorf Rich Stevens显然不是Dennis Richie, Brian Kernighan那个贝尔实验室圈子的人。他对Unix的深入了解,是自己翻烂手册、钻研系统得到的。这个切入点,和我们多数用户是一样的。所以,我们想知道的东西,也许正是Stevens关心过的。看看他在N个系统上做的代码测试和对不同标准的比较就知道。...... (13回应)2007-08-10 23/26有用来自 人民邮电出版社2006版
技术书籍的典范
-
- 史提夫孫 好书的妙处之一,就是能给你与作者交流的感觉。技术书籍常犯两个毛病,一个是着眼点太低,堆砌细节(比如谭浩强的《C程序设计》),读起来好像听和尚念经,无法交流。再一个就是着眼点太高,兜售哲学(比如ESR的《The Art of UNIX Programming》),读起来好像听于丹老师讲论语,不敢交流。此书的经典性就在于不...... (5回应)2009-08-01 14/15有用来自 人民邮电出版社2006版
UNIX编程必备的参考书--圣经
-
- 刀巴(签名党) 虽然作者不幸离开了我们,虽然是本讲述Unix而不是Linux编程环境的书,虽然是一本有点历史的书。但是任何希望对Unix/Linux系统有进一步的了解的人不能不读这本书。 纷繁复杂的Unix系统,在作者手下,若庖丁解牛,娓娓道来。同时,本书的翻译也颇为到位,技术名词准确,文章也没有生涩的感觉。 本书未提到的网络部分...... (3回应)2005-12-02 10/11有用来自 机械工业出版社2000版
适合老手查阅和补充知识,不建议新手入门时翻阅
-
- 炎伯 适合老手查阅和补充知识,不建议新手入门时翻阅。原因是本书针对的是unix标准接口,而实际上各家遵循unix标准并不是那么完整,所以你会发现对书上的代码进行验证时往往得不到期望的结果;再有,本书的例程也比较意识流,对章节知识点的代表性不足。总之新手翻阅本书会头大的...... (9回应)2009-11-05 11/14有用
是程序的bug,还是我自己理解的问题(printd.c)?
-
- liuh(要加油!) 第21章,与网络打印机通信 printd.c的代码中,从863到878行,如果读的缓冲区刚好在"Content-Length:xxxx"(xxxx代表一个数字)中的数字部分截断,那得到的content-length就不是真实长度了。 求证。...... (5回应)2012-01-04
我认为很好,但也没有上面的人说的那么好
-
- hp 或许是因为我不是第一次接触系统编程,或许我看过《Windows核心编程》,我一直觉得这本书没有《windows核心编程》那么精彩。 APUE覆盖的范围很广,但是有些地方感觉不太详细。算了,先写到这里......2011-12-14
"UNIX环境高级编程"的论坛 · · · · · ·
| 翻译的很绕口 | 来自coredump | 1 回应 | 2011-12-19 |
| 买书送T-Shirt | 来自豆他爹 | 1 回应 | 2010-09-15 |
| 再版一次贵了n倍, 还好我大学毕业的时候就买了 | 来自number5 | 2007-06-30 | |
| 购买UNIX环境高级编程-(第2版) 即随单赠送精品图书... | 来自china-pub | 2010-09-14 | |
| UNIX环境高级编程-(第2版) 样张试读 | 来自china-pub | 2010-09-14 |
> 浏览更多话题
在哪儿买这本书? · · · · · ·
这本书的其他版本 · · · · · · ( 全部5 )
- Addison-Wesley Professional版 2005-06-17 / 62人读过 / 有售
- 机械工业出版社版 2000-2-1 / 423人读过
- 人民邮电出版社版 2006-2-1 / 180人读过 / 有售
- 机械工业出版社版 2002-1-1 / 119人读过
以下豆列推荐 · · · · · · (全部)
- 豆瓣评分>9的书(100人以上) (阿獠)
- 那年的教科书 (陈永仁)
- 豆瓣评分>9的计算机图书 (DDD)
- Linux网络程序设计 (叶 子)
- 数学计算机专业书籍 (我叫点点点)
谁读这本书?
喜欢这本书的人常去的小组 · · · · · ·

- Vim (6198)

- Linux (6610)

- Python编程 (18998)

- Freebsd (1057)

- 开源 (4098)

- LISP (2011)

- Erlang (1030)

- Emacs (2343)
喜欢这本书的人关注的活动 · · · · · ·
订阅关于UNIX环境高级编程的评论:
feed: rss 2.0











