您好,欢迎光临有路网!
Linux环境高级程序设计
QQ咨询:
有路璐璐:

Linux环境高级程序设计

  • 作者:黄茹、王小银、张丽丽
  • 出版社:清华大学出版社
  • ISBN:9787302520252
  • 出版日期:2019年02月01日
  • 页数:0
  • 定价:¥59.00
  • 分享领佣金
    手机购买
    城市
    店铺名称
    店主联系方式
    店铺售价
    库存
    店铺得分/总交易量
    发布时间
    操作

    新书比价

    网站名称
    书名
    售价
    优惠
    操作

    图书详情

    内容提要
    本书介绍使用C语言结合Linux API进行系统级程序设计的方法,主要包括Linux基础知识、C程序开发工具、文件及目录管理、进程管理、重定向与管道、信号、进程间通信、线程、线程间的同步机制、网络程序设计等10章,以及10个实验,全面而系统地介绍Linux操作系统各种机制的实现原理、经常使用的系统接口函数、系统接口和命令程序之间的关系以及命令程序的实现过程等。 本书结构清晰,适合于教学,为各类高等学校开设开源软件程序设计课程提供了一个切实可行的思路,同时也可作为培训教材在各类培训机构使用。书中各章节划分明确,各章突出不同的**,有利于教师组织安排授课内容;同时提供设计精美、内容丰富的电子教案以及教学素材供授课教师使用,有效地减轻了授课教师备课的工作量和强度。 本书目标读者为具有一定C语言基础的读者,适合各类高等院校的计算机及相关专业学生、Linux培训机构、Linux API编程爱好者、Linux程序开发人员及爱好者学习使用。
    文章节选
    第5章重定向与管道在Linux系统中,系统会默认为命令或程序打开三个标准I/O文件,保证命令或程序可以与用户进行交互。除此之外,还可以将这三个标准文件重定向,借此可以实现从指定的位置获取输入信息或将输出信息、错误信息保存在指定的文件中。同时,Linux系统还提供管道的功能,可以将多条命令或程序之间的输出和输入相衔接,实现灵活的Shell编程。
    5.1重定向和管道命令〖4/5〗5.1.1重定向命令所有的UNIX I/O重定向都是基于标准数据流的原理。在Shell中键入命令运行时,内核将会为命令进程打开三个标准I/O设备文件,并且用文件���述符0、1、2与它们关联,其中文件描述符0对应标准输入设备,1对应标准输出设备,2对应标准错误文件。进程在运行过程中,默认从标准输入设备文件读取数据,将输出数据写入标准输出设备文件,如果出错的话,错误信息将会写入标准错误文件。例如,使用cat命令时,系统将会把结果显示在标准输出设备上。通常标准输入设备文件为键盘,标准输出设备文件和标准错误文件为显示器,如图5.1所示。
    图5.1进程和标准设备文件的联系
    在某种情况下,用户希望能够将信息输出到某个文件中,而不是显示在标准输出设备上,此时可以将该进程的标准输出进行重定向。重定向命令分为输入重定向、输出重定向和错误重定向。〖1〗Linux环境**程序设计第5章重定向与管道[3]〖3〗1. 输入重定向
    输入重定向使用符号“<”来表示,它表示将进程的文件描述符0关联到指定的文件上去。输入重定向命令的格式为: command <file例如,命令mail s test hr@163.com<file就是一条输入重定向命令,它表示以file文件为邮件内容,向hr@163.com邮箱发送一封标题为test的邮件。使用“<”符号时,也可以把文件描述符0加在前面,例如,cat 0<file1,该命令同样表示将cat命令的输入重定向到file1文件。
    2. 输出重定向
    符号“>”或“>>”都可以用来表示输出重定向,两者的差异在于: 前者以覆盖的方式输出,后者以追加的方式输出。输出重定向命令的格式为: command>file或 command>>file例如,命令cat file1 file2>file3表示将文件file1和file2的内容合并输出到文件file3中,这条命令也可以使用以下两条命令来替换: cat file1>file3
    cat file2>>file3如果重定向使用的是符号“>!”,那么表示输出重定向强制覆盖文件原有的内容。
    3. 错误重定向
    错误重定向可以使用符号“2>”或“2>>”来表示,两个符号的差异与输出重定向类似。错误重定向的具体命令格式为: command 2>file或command 2>>file使用错误重定向后,如果在命令执行的过程中有错误发生,错误信息将会记录在文件file中。
    除了以上介绍的重定向符号外,还可以使用“>&”“1>”“2>&1”等符号。使用重定向符号时,也并不**于只能在命令末尾处出现重定向符号。这些重定向符号可以单独使用,也可以组合使用,例如: wc <file1 >result.wc 2>error.txt以上命令表示统计file1文件的字符、单词和行数,将结果记录在result.wc文件中,如果出错,错误信息记录在error.txt文件中。
    5.1.2管道命令
    如果某些数据必须要经过几次命令操作之后才能得到所想要的结果,此时可以使用管道符号将这些命令连接起来。管道命令会将符号先后的命令连接起来,将前一条命令的输出作为后一条命令的输入。符号“|”称为管道操作符,管道命令的具体格式如下: command1|command2|command3|……例如: grep root /etc/passwd | sort图5.2管道命令示意图
    该命令表示在/etc/passwd文件中搜索出含有root的内容,并将这些内容排序。这条管道命令的示意图如图5.2所示。
    又如: ls -l|grep hr|lpr该命令表示列出当前目录中包含hr模式串的文件名称,将结果打印出来。
    5.2实现重定向〖4/5〗5.2.1重定向的实施者在实现重定向命令之前,需要借由一个示例程序先来明确一下重定向是由待执行的命令或程序还是Shell来实现的。 \[示例程序5.1 for_redirect.c\]
    #include<stdio.h>
    main(int argc, char  argv\[ \])
    {
    int i;
    char buf\[80\];
    scanf("%s",buf);
    printf("info from file:%s\\n",buf);
    printf("arg list\\n");
    for(i=0;i<argc;i )
    printf("argv\[%d\]:%s\\n",i,argv\[i\]);
    fprintf(stderr,"where do you find this?\\n");
    }在示例程序5.1中,分别使用scanf、printf和fprintf函数对标准输入、标准输出和标准错误文件进行了读、写操作,并且还使用printf函数输出了执行程序时所附带的参数。当使用两种不同的方式来运行该程序时,请观察一下重定向符号是否会被Shell当作参数传递给用户程序。
    将程序编译后按照带重定向和不带重定向两种方式运行,得到结果如下: root@ubuntu:~#./for_redirect para1 para2 para3
    Hello
    info from file:Hello
    arg list
    argv\[0\]:./for_redirect
    argv\[1\]:para1
    argv\[2\]:para2
    argv\[3\]:para3
    where do you find this?
    root@ubuntu:~#./for_redirect para1 para2 para3>result 2>err.txt
    Hello
    root@ubuntu:~#cat result
    info from file:Hello
    arg list
    argv\[0\]:./for_redirect
    argv\[1\]:para1
    argv\[2\]:para2
    argv\[3\]:para3
    root@ubuntu:~#cat err.txt
    where do you find this?从程序两次运行的输出结果来看,输出的参数中并没有重定向符号和文件名称,因此可以确定: 重定向并不是由命令或用户程序实现的,而是由Shell实现的。因此可以明确: 要实现重定向命令,就需要改写第4章所编写的简单Shell程序,在Shell执行命令之前添加实现重定向的功能。
    5.2.2实现重定向的前提条件
    当着手设计带有重定向功能的Shell程序时,还要谨记: 之所以能够实现重定向,是因为Linux环境具有以下几个特性:
    (1) 系统为每个进程所打开的标准I/O设备文件对应着值*小的三个文件描述符0、1、2。实际上一个进程打开的所有文件的信息是储存在一个结构体数组之中的,而打开文件对应的文件描述符就是该文件信息在结构体数组中的存储位置,即数组的下标。
    (2) 当进程使用open、dup等文件操作时,新分配的文件描述符遵循*低可用文件描述符原则。即当打开一个文件时,系统为此文件安排的文件描述符总是可用的文件描述符中值*小的那一个。
    (3) 在一个进程中,如果在文件打开操作以后使用了eXec族函数,那么eXec函数将不会影响执行前打开的文件描述符集合。
    5.2.3dup和dup2
    dup和dup2是在Linux中实现重定向命令时经常会使用到的两个函数。两者都可用于复制文件描述符,dup函数的接口规范说明如表5.1所示。续表表5.1dup函数的接口规范说明
    函数名称dup函数功能复制一个文件描述符头文件#include<unistd.h>函数原型int dup(int oldfd);参数oldfd: 被复制的文件描述符返回值>-1: 复制成功,返回新的文件描述符
    -1: 出错dup函数用来复制一个文件描述符,参数oldfd指向一个打开的文件,函数的返回值返回复制后的新文件描述符,新的文件描述符也指向oldfd所指向的文件列表项,如图5.3所示,如果该进程没有打开其他文件,那么在执行了dup(0)之后,文件描述符3将会指向0所对应的文件。
    图5.3dup(0) 后文件描述符的关系
    dup2也可用于复制文件描述符,它与dup的不同之处在于,dup2可以指定要把信息复制给哪一个文件描述符。dup2函数的接口规范说明如表5.2所示。表5.2dup2函数的接口规范说明
    函数名称dup2函数功能复制一个文件描述符头文件#include<unistd.h>函数原型int dup2(int oldfd, int newfd);参数oldfd: 被复制的文件描述符
    newfd: 新的文件描述符返回值> -1: 复制成功,返回新的文件描述符
    -1: 出错说明: dup2在复制文件描述符时,如果newfd已分配给某个打开的文件,那么系统会先关闭newfd,切断与原先文件的联系,然后再进行复制。
    示例程序5.2说明了如何使用dup和dup2来复制文件描述符。 \[示例程序5.2 exp_dup.c\]
    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<fcntl.h>

    main()
    {
    int fd,fd1,fd2;
    char buf\[10\];
    fd=open("text.txt",O_RDONLY);
    if(fd<0)
    {
    perror("open");
    exit(EXIT_FAILURE);
    }
    fd1=dup(fd);
    if(fd1<0)
    {
    perror("dup");
    exit(EXIT_FAILURE);
    }
    fd2=dup2(fd,5);
    if(fd2<0)
    {
    perror("dup2");
    exit(EXIT_FAILURE);
    }
    if(read(fd,buf,10)>0)
    write(STDOUT_FILENO,buf,10);
    if(read(fd1,buf,10)>0)
    write(STDOUT_FILENO,buf,10);
    if(read(fd2,buf,10)>0)
    write(STDOUT_FILENO,buf,10);
    close(fd);
    close(fd1);
    close(fd2);
    }编译后运行,得到程序的运行结果如下: root@ubuntu:~#cat text.txt
    This is a test text,
    Can you see my greeting?
    root@ubuntu:~#./exp_dup
    This is a test text,
    Can you s从运行结果可以看出,fd通过open函数分配给了文件text.txt,文件描述符fd1和fd2都复制了fd,因此三个文件描述符指向同一个文件。尽管fd、fd1和fd2是三个不同的文件描述符,但它们使用的是同一个打开的文件表项(struct file)。因此不管通过哪个文件描述符改变了文件读写指针的位置,都会对其他两个文件描述符造成影响。从这个示例的运行结果也能够看到,输出结果并不是三次从头开始的10个字符,而是从头开始连续的30个字符。
    5.2.4重定向的三种方法
    通过上一节的学习,可以分析出实现重定向的流程: 0、1、2三个文件描述符原先是与标准I/O设备文件关联的,需要重定向时,可以使用open、dup或dup2等函数将文件描述符0、1或2与指定的重定向文件相关联,这样就可以实现标准I/O设备文件的重定向。在Linux系统中,可以使用三种方法来实现重定向功能,分别是:
     close then open: 关闭指定的标准I/O设备文件,打开重定向文件。
     open close dup close: 打开重定向文件,关闭指定的标准I/O设备文件,复制重定向文件的文件描述符,关闭**步打开的文件描述符。
     open dup2 close: 打开重定向文件,将指定的标准I/O设备文件描述符作为参数,复制重定向文件的文件描述符,关闭**步打开的文件描述符。
    针对以上三种重定向的方法,我们来一一讲解。
    1. close then open
    在这种方法中,程序调用close函数关闭指定的文件描述符与标准设备文件的联系,此时该文件描述符就处于空闲可分配状态;随后使用open函数打开指定的重定向文件,由于open遵循*低可用文件描述符原则,打开的文件将获得**步操作释放出来的文件描述符。示例程序5.3实现了将标准输入重定向: \[示例程序5.3 exp_redirect1.c\]
    #include<stdio.h>
    #include<stdlib.h>
    #include<fcntl.h>
    main()
    {
    int fd;
    char buf\[80\];
    close(0);
    if((fd=open("./text.txt",O_RDONLY))!=0)
    {
    perror("open");
    exit(EXIT_FAILURE);
    }
    read(0,buf,80);
    write(1,buf,80);
    }该程序将标准输入重定向到当前目录中的text.txt文件,从中读取80个字节的数据,输出在标准输出设备上。文件描述符0关联的文件变化情况如图5.4所示。
    图5.4close then open方法的示意图
    2. open close dup close
    这种方法首先使用open函数打开指定的重定向文件,获取该文件的文件描述符fd;随后,使用close函数关闭标准I/O文件,释放其对应的文件描述符;之后使用dup函数复制fd,此时由于dup函数遵循*低可用文件描述符原则,因此将会把fd复制给第二步中close释放出来的文件描述符;*后使用close关闭fd即可。示例程序5.4使用第二种方法来实现重定向,其功能和示例程序5.3一样,将输入重定向到当前目录中的text.txt文件上。 \[示例程序5.4 exp_redirect2.c\]
    main()
    {
    int fd,newfd;
    char buf\[80\];
    fd=open("./text.txt ",O_RDONLY);
    close(0);
    newfd=dup(fd);
    if(newfd!=0)
    {
    perror("dup");
    exit(EXIT_FAILURE);
    }
    close(fd);
    read(0,buf,80);
    write(1,buf,80);
    }在这个示例程序中,文件描述符关联文件的变化情况如图5.5所示。
    图5.5open close dup close的过程
    3. open dup2 close
    这种方法与open close dup close方法类似,不同之处在于,使用dup2将open close dup close方法的第二步和第三步合而为一,直接关闭了标准I/O文件并进行了文件描述符的复制。示例程序5.5为使用方法三实现输入重定向的代码。 \[示例程序5.5 exp_redirect3.c\]
    main()
    {
    int fd,newfd;
    char buf\[80\];
    fd=open("./text.txt ",O_RDONLY);
    newfd=dup2(fd,0);
    if(newfd!=0)
    {
    perror("dup2");
    exit(EXIT_FAILURE);
    }
    close(fd);
    read(0,buf,80);
    write(1,buf,80);
    }以上三种方法均可以实现重定向操作,具体使用哪种方法可以根据实际情况来决定。如果已知重定向文件的文件名,那么三种方法都可以实现;但如果在程序运行过程中只能获取重定向文件的文件描述符,那么就要考虑使用后面两种方法。
    5.2.5ls l>list.txt
    为了使读者能够更好地掌握如何在简单Shell中实现重定向功能,我们先来学习一个具体的重定向命令如何实现: ls -l>list.txt首先,先来分析一下Shell在实现ls l命令时的过程是怎样的。从第4章了解到当Shell执行一条前台命令时,将会为命令创建一个子进程;随后在进程中使用eXec函数来执行命令程序,此时Shell进程处于阻塞状态等待命令进程结束;当命令进程结束后,Shell将会显示命令进程运行的结果。从这个过程中可以发现:
    (1) 命令进程需要进行重定向,但是Shell进程并不需要重定向。
    (2) 为了执行命令,Shell需要调用fork函数创建子进程,子进程需要调用eXec函数来执行ls l命令。这就要求必须在创建了子进程之后,调用eXec函数之前将子进程的输出重定向到文件list.txt。这样一来,重定向仅仅是针对子进程的,并且子进程在调用eXec函数时,并不会影响到在eXec函数执行前已打开的文件描述符列表。
    (3) 由于list.txt有可能是一个不存在的文件,还需要将重定向的三种方法中的open函数换成creat函数。
    程序代码如示例程序5.6所示。 \[示例程序5.6 exp_lsre.c\]
    main()
    {
    int pid,fd;
    printf("This is to show how to redirect!\\n");
    if((pid=fork())==-1)
    {
    perror("fork");
    exit(EXIT_FAILURE);
    }
    else if(pid==0)
    {
    close(1);
    fd=creat("list.txt",0644);
    if(execlp("ls","ls","-l",NULL)<0)
    {
    perror("exec");
    exit(EXIT_FAILURE);
    }
    }
    else if(pid!=0)
    {
    wait(NULL);
    system("cat list.txt");
    }
    }示例程序5.6使用了close then open来实现重定向。请读者思考一下,命令ls l>>list.txt、ls l 2>err.txt应该如何实现?
    从示例程序5.6中,可以分析出在简单Shell程序中实现重定向的流程如下:
    (1) 以字符串的方式读入命令后,将命令字符串分解为命令名称、参数、选项、重定向等各个分项。
    (2) 如果存在重定向符号,则需要根据重定向符号的类型,分解出重定向文件名和需要重定向的标准I/O文件。
    (3) 调用fork创建子进程,在子进程中按照重定向的要求,重定向标准I/O文件,父进程调用wait等待子进程结束。
    目录
    目录 第1章Linux基础知识/1 1.1Linux简介1 1.1.1Linux系统的发展1 1.1.2与Linux相关的一些知识3 1.2Linux系统编程5 1.2.1什么是系统编程5 1.2.2系统编程的学习内容及方法6 1.2.3一个例子7 1.2.4系统调用和库函数10 1.3常用工具及命令10 1.3.1命令格式10 1.3.2常用工具11 1.3.3常用命令15 1.3.4获取帮助17 1.4小结20 习题20 第2章C程序开发工具/22 2.1编辑工具22 2.1.1编辑工具介绍22 2.1.2vi和vim程序编辑器25 2.2gcc编译器34 2.3gdb调试器36 2.3.1启动和退出gdb37 2.3.2显示和查找程序源代码38 2.3.3执行程序和获取帮助39 2.3.4设置和管理断点40 2.3.5查看和设置变量的值45 2.3.6控制程序的执行46 2.4make和Makefile48〖1〗Linux环境**程序设计目录[3]〖3〗2.4.1make命令48 2.4.2编写Makefile文件50 2.5小结54 习题55 第3章文件及目录管理/56 3.1文件和I/O操作分类56 3.1.1文件概念56 3.1.2文件操作分类56 3.2Linux文件系统概述58 3.2.1文件结构58 3.2.2文件系统模型59 3.2.3目录、索引结点和文件描述符60 3.2.4文件的分类63 3.2.5文件访问权限控制64 3.3文件的读写68 3.3.1文件打开、创建和关闭69 3.3.2文件的读写72 3.3.3文件读写指针的移动80 3.3.4标准I/O的文件流82 3.4文件属性及相关系统调用87 3.4.1获取文件属性87 3.4.2修改文件的访问权限91 3.4.3修改文件的用户属性93 3.4.4获取用户的信息94 3.4.5改变文件大小95 3.4.6获取文件的时间属性96 3.5目录操作97 3.5.1打开目录97 3.5.2读取目录项98 3.5.3关闭目录98 3.6实现自己的ls命令100 3.7小结105 习题106 第4章进程管理/107 4.1Linux可执行程序的存储结构与进程结构107 4.1.1Linux可执行程序的存储结构107 4.1.2Linux系统的进程结构109 4.1.3进程树110 4.2进程的环境和进程属性111 4.2.1进程的环境111 4.2.2进程的状态112 4.2.3进程的基本属性115 4.2.4进程的用户属性121 4.3进程管理124 4.3.1创建进程124 4.3.2在进程中运行新代码127 4.3.3vfork函数131 4.3.4进程退出133 4.3.5wait函数138 4.3.6Shell的实现流程142 4.4Linux中的特殊进程143 4.4.1孤儿进程143 4.4.2僵尸进程144 4.4.3守护进程145 4.4.4出错记录148 4.5小结150 习题150 第5章重定向与管道/151 5.1重定向和管道命令151 5.1.1重定向命令151 5.1.2管道命令152 5.2实现重定向153 5.2.1重定向的实施者153 5.2.2实现重定向的前提条件154 5.2.3dup和dup2154 5.2.4重定向的三种方法157 5.2.5ls l>list.txt159 5.3管道编程161 5.3.1匿名管道161 5.3.2命名管道165 5.3.3ls l|grep root168 5.3.4popen和pclose170 5.4小结173 习题174 第6章信号/175 6.1信号概述175 6.1.1什么是信号175 6.1.2信号的来源和处理过程177 6.1.3信号的处理方式177 6.2早期信号处理函数——signal178 6.2.1signal函数实现信号的三种处理方式178 6.2.2signal函数存在的问题182 6.3信号处理函数——sigaction183 6.3.1sigaction系统调用183 6.3.2sigaction函数参数的说明186 6.4信号其他相关函数190 6.4.1kill与raise190 6.4.2alarm与pause192 6.4.3实现sleep函数193 6.5小结194 习题195 第7章进程间通信/196 7.1选择进程间通信方式196 7.1.1文件实现进程间通信196 7.1.2命名管道实现进程间通信199 7.2共享内存201 7.2.1什么是共享内存201 7.2.2共享内存相关系统调用203 7.2.3共享内存实现进程间通信206 7.2.4三种通信方式的比较208 7.3信号量209 7.3.1信号量及相关系统调用209 7.3.2使用信号量控制对共享内存的访问214 7.3.3信号量机制总结221 7.4System V IPC222 7.4.1Linux中的进程通信机制222 7.4.2System V IPC概述223 7.4.3IPC的标识符和键224 7.5消息队列225 7.5.1消息队列的概念225 7.5.2消息队列相关系统调用226 7.5.3使用消息队列实现进程间通信229 7.6小结232 习题232 第8章线程/233 8.1线程概述233 8.1.1线程的定义233 8.1.2用户级线程和内核级线程234 8.1.3线程与进程的对比234 8.2线程基本操作235 8.2.1线程创建235 8.2.2线程退出/等待238 8.2.3线程终止244 8.2.4线程挂起247 8.2.5线程的分离249 8.2.6线程的一次性初始化251 8.2.7线程的私有数据253 8.3线程属性257 8.3.1线程属性对象258 8.3.2设置/获取线程detachstate属性260 8.3.3设置与获取线程栈相关属性261 8.4线程应用举例266 8.5小结273 习题273 第9章线程间的同步机制/275 9.1互斥锁275 9.1.1互斥锁基本原理275 9.1.2互斥锁基本操作275 9.1.3互斥锁应用实例278 9.2条件变量279 9.2.1条件变量基本原理279 9.2.2条件变量基本操作279 9.2.3条件变量应用实例281 9.3读写锁284 9.3.1读写锁基本原理284 9.3.2读写锁基本操作284 9.3.3读写锁应用实例287 9.4线程与信号289 9.4.1线程信号管理290 9.4.2线程信号应用实例291 9.5小结295 习题295 第10章网络程序设计/296 10.1网络知识基础296 10.1.1TCP/IP参考模型296 10.1.2Linux中TCP/IP网络的层结构296 10.1.3TCP协议297 10.1.4UDP协议298 10.2套接字299 10.2.1套接字概述299 10.2.2套接字编程接口300 10.2.3套接字通信流程303 10.3套接字基础307 10.3.1套接字地址结构307 10.3.2字节顺序309 10.3.3字节处理函数310 10.4套接字编程311 10.4.1基于TCP协议的网络通信311 10.4.2基于UDP协议的网络通信316 10.5小结319 习题319 附录实验/321 实验1Linux基础知识321 实验2C程序开发工具321 实验3文件I/O操作322 实验4进程管理及守护进程323 实验5重定向和管道编程323 实验6信号安装及处理方式324 实验7System V IPC进程通信325 实验8线程管理325 实验9线程间通信326 实验10套接字编程326

    与描述相符

    100

    北京 天津 河北 山西 内蒙古 辽宁 吉林 黑龙江 上海 江苏 浙江 安徽 福建 江西 山东 河南 湖北 湖南 广东 广西 海南 重庆 四川 贵州 云南 西藏 陕西 甘肃 青海 宁夏 新疆 台湾 香港 澳门 海外