第34章 进程组、会话和作业控制 573
34.1 概述 573
34.2 进程组 575
34.3 会话 577
34.4 控制终端和控制进程 578
34.5 前台和后台进程组 580
34.6 SIGHUP信号 581
34.6.1 在shell中处理SIGHUP信号 581
34.6.2 SIGHUP和控制进程的终止 583
34.7 作业控制 585
34.7.1 在shell中使用作业控制 585
34.7.2 实现作业控制 587
34.7.3 处理作业控制信号 591
34.7.4 孤儿进程组(SIGHUP回顾) 594
34.8 总结 598
34.9 习题 599
第35章 进程优先级和调度 600
35.1 进程优先级(nice值) 600
35.2 实时进程调度概述 603
35.2.1 SCHED RR策略 604
35.2.2 SCHED FIFO策略 605
35.2.3 SCHED BATCH和SCHED IDLE策略 605
35.3 实时进程调用API 605
35.3.1 实时优先级范围 606
35.3.2 修改和获取策略和优先级 606
35.3.3 释放CPU 611
35.3.4 SCHED RR时间片 611
35.4 CPU亲和力 612
35.5 总结 614
35.6 习题 615
第36章 进程资源 617
36.1 进程资源使用 617
36.2 进程资源限制 619
36.3 特定资源限制细节 623
36.4 总结 627
36.5 习题 627
第37章 DAEMON 628
37.1 概述 628
37.2 创建一个daemon 629
37.3 编写daemon指南 632
37.4 使用SIGHUP重新初始化一个daemon 632
37.5 使用syslog记录消息和错误 635
37.5.1 概述 635
37.5.2 syslog API 636
37.5.3 /etc/syslog.conf文件 640
37.6 总结 641
37.7 习题 641
第38章 编写安全的特权程序 642
38.1 是否需要一个Set-User-ID或Set-Group-ID程序? 642
38.2 以最小权限操作 643
38.3 小心执行程序 645
38.4 避免暴露敏感信息 646
38.5 确定进程的边界 647
38.6 小心信号和竞争条件 647
38.7 执行文件操作和文件I/O的缺陷 648
38.8 不要完全相信输入和环境 648
38.9 小心缓冲区溢出 649
38.10 小心拒绝服务攻击 650
38.11 检查返回状态和安全地处理失败情况 651
38.12 总结 651
38.13 习题 652
第39章 能力 653
39.1 能力基本原理 653
39.2 Linux能力 654
39.3 进程和文件能力 654
39.3.1 进程能力 654
39.3.2 文件能力 655
39.3.3 进程许可和有效能力集的目的 657
39.3.4 文件许可和有效能力集的目的 657
39.3.5 进程和文件可继承集的目的 658
39.3.6 在shell中给文件赋予能力和查看文件能力 658
39.4 现代能力实现 659
39.5 在exec()中转变进程能力 659
39.5.1 能力边界集 660
39.5.2 保持root语义 660
39.6 改变用户ID对进程能力的影响 661
39.7 用编程的方式改变进程能力 661
39.8 创建仅包含能力的环境 665
39.9 发现程序所需的能力 667
39.10 不具备文件能力的老式内核和系统 667
39.11 总结 669
39.12 习题 669
第40章 登录记账 670
40.1 utmp和wtmp文件概述 670
40.2 utmpx API 671
40.3 utmpx结构 671
40.4 从utmp和wtmp文件中检索信息 673
40.5 获取登录名称:getlogin() 676
40.6 为登录会话更新utmp和wtmp文件 677
40.7 lastlog文件 681
40.8 总结 683
40.9 习题 683
第41章 共享库基础 684
41.1 目标库 684
41.2 静态库 685
41.3 共享库概述 686
41.4 创建和使用共享库——首回合 687
41.4.1 创建一个共享库 687
41.4.2 位置独立的代码 687
41.4.3 使用一个共享库 688
41.4.4 共享库soname 689
41.5 使用共享库的有用工具 691
41.6 共享库版本和命名规则 692
41.7 安装共享库 694
41.8 兼容与不兼容库比较 696
41.9 升级共享库 697
41.10 在目标文件中指定库搜索目录 698
41.11 在运行时找出共享库 700
41.12 运行时符号解析 700
41.13 使用静态库取代共享库 701
41.14 总结 702
41.15 习题 703
第42章 共享库高级特性 704
42.1 动态加载库 704
42.1.1 打开共享库:dlopen() 705
42.1.2 错误诊断:dlerror() 706
42.1.3 获取符号的地址:dlsym() 707
42.1.4 关闭共享库:dlclose() 709
42.1.5 获取与加载的符号相关的信息:dladdr() 710
42.1.6 在主程序中访问符号 710
42.2 控制符号的可见性 710
42.3 链接器版本脚本 711
42.3.1 使用版本脚本控制符号的可见性 712
42.3.2 符号版本化 713
42.4 初始化和终止函数 715
42.5 预加载共享库 716
42.6 监控动态链接器:LD_DEBUG 716
42.7 总结 717
42.8 习题 718
第43章 进程间通信简介 719
43.1 IPC工具分类 719
43.2 通信工具 720
43.3 同步工具 721
43.4 IPC工具比较 723
43.5 总结 727
43.6 习题 727
第44章 管道和FIFO 728
44.1 概述 728
44.2 创建和使用管道 730
44.3 将管道作为一种进程同步的方法 735
44.4 使用管道连接过滤器 737
44.5 通过管道与Shell命令进行通信:popen() 739
44.6 管道和stdio缓冲 743
44.7 FIFO 743
44.8 使用管道实现一个客户端/服务器应用程序 745
44.9 非阻塞I/O 751
44.10 管道和FIFO中read()和write()的语义 752
44.11 总结 753
44.12 习题 754
第45章 System V IPC介绍 756
45.1 概述 757
45.2 IPC Key 759
45.3 关联数据结构和对象权限 761
45.4 IPC标识符和客户端/服务器应用程序 763
45.5 System V IPC get调用使用的算法 764
45.6 ipcs和ipcrm命令 766
45.7 获取所有IPC对象列表 767
45.8 IPC限制 767
45.9 总结 768
45.10 习题 768
第46章 System V消息队列 769
46.1 创建或打开一个消息队列 769
46.2 交换消息 771
46.2.1 发送消息 772
46.2.2 接收消息 774
46.3 消息队列控制操作 777
46.4 消息队列关联数据结构 778
46.5 消息队列的限制 780
46.6 显示系统中所有消息队列 781
46.7 使用消息队列实现客户端/服务器应用程序 783
46.8 使用消息队列实现文件服务器应用程序 784
46.9 System V消息队列的缺点 790
46.10 总结 790
46.11 习题 791
第47章 System V信号量 792
47.1 概述 793
47.2 创建或打开一个信号量集 795
47.3 信号量控制操作 796
47.4 信号量关联数据结构 798
47.5 信号量初始化 801
47.6 信号量操作 803
47.7 多个阻塞信号量操作的处理 809
47.8 信号量撤销值 810
47.9 实现一个二元信号量协议 811
47.10 信号量限制 814
47.11 System V信号量的缺点 815
47.12 总结 816
47.13 习题 817
第48章 System V共享内存 818
48.1 概述 818
48.2 创建或打开一个共享内存段 819
48.3 使用共享内存 820
48.4 示例:通过共享内存传输数据 821
48.5 共享内存在虚拟内存中的位置 825
48.6 在共享内存中存储指针 828
48.7 共享内存控制操作 829
48.8 共享内存关联数据结构 830
48.9 共享内存的限制 832
48.10 总结 833
48.11 习题 833
第49章 内存映射 835
49.1 概述 835
49.2 创建一个映射:mmap() 837
49.3 解除映射区域:munmap() 840
49.4 文件映射 840
49.4.1 私有文件映射 841
49.4.2 共享文件映射 842
49.4.3 边界情况 845
49.4.4 内存保护和文件访问模式交互 846
49.5 同步映射区域:msync() 847
49.6 其他mmap()标记 848
49.7 匿名映射 849
49.8 重新映射一个映射区域:mremap() 852
49.9 MAP_NORESERVE和过度利用交换空间 853
49.10 MAP_FIXED标记 854
49.11 非线性映射:remap_file_pages() 855
49.12 总结 857
49.13 习题 858
第50章 虚拟内存操作 859
50.1 改变内存保护:mprotect() 859
50.2 内存锁:mlock()和mlockatt() 861
50.3 确定内存驻留性:mincore() 864
50.4 建议后续的内存使用模式:madvise() 866
50.5 小结 868
50.6 习题 868
第51章 POSIX IPC介绍 869
51.1 API概述 869
51.2 System V IPC与POSIX IPC比较 872
51.3 总结 873
第52章 POSIX消息队列 874
52.1 概述 874
52.2 打开、关闭和断开链接消息队列 875
52.3 描述符和消息队列之间的关系 877
52.4 消息队列特性 878
52.5 交换消息 882
52.5.1 发送消息 882
52.5.2 接收消息 883
52.5.3 在发送和接收消息时设置超时时间 885
52.6 消息通知 886
52.6.1 通过信号接收通知 887
52.6.2 通过线程接收通知 889
52.7 Linux特有的特性 891
52.8 消息队列限制 892
52.9 POSIX和System V消息队列比较 893
52.10 总结 894
52.11 习题 894
第53章 POSIX信号量 895
53.1 概述 895
53.2 命名信号量 895
53.2.1 打开一个命名信号量 896
53.2.2 关闭一个信号量 898
53.2.3 删除一个命名信号量 898
53.3 信号量操作 899
53.3.1 等待一个信号量 899
53.3.2 发布一个信号量 901
53.3.3 获取信号量的当前值 901
53.4 未命名信号量 903
53.4.1 初始化一个未命名信号量 904
53.4.2 销毁一个未命名信号量 906
53.5 与其他同步技术比较 906
53.6 信号量的限制 907
53.7 总结 908
53.8 习题 908
第54章 POSIX共享内存 909
54.1 概述 909
54.2 创建共享内存对象 910
54.3 使用共享内存对象 913
54.4 删除共享内存对象 915
54.5 共享内存APIs比较 915
54.6 总结 916
54.7 习题 917
第55章 文件加锁 918
55.1 概述 918
55.2 使用flock()给文件加锁 920
55.2.1 锁继承与释放的语义 922
55.2.2 flock()的限制 923
55.3 使用fcntl()给记录加锁 923
55.3.1 死锁 928
55.3.2 示例:一个交互式加锁程序 928
55.3.3 示例:一个加锁函数库 931
55.3.4 锁的限制和性能 933
55.3.5 锁继承和释放的语义 934
55.3.6 锁定饿死和排队加锁请求的优先级 935
55.4 强制加锁 935
55.5 /proc/locks文件 938
55.6 仅运行一个程序的单个实例 939
55.7 老式加锁技术 941
55.8 总结 942
55.9 习题 943
第56章 SOCKET:介绍 945
56.1 概述 945
56.2 创建一个socket:socket() 948
56.3 将socket绑定到地址:bind() 948
56.4 通用socket地址结构:struct sockaddr 949
56.5 流socket 950
56.5.1 监听接入连接:listen() 951
56.5.2 接受连接:accept() 952
56.5.3 连接到对等socket:connect() 952
56.5.4 流socket I/O 953
56.5.5 连接终止:close() 953
56.6 数据报socket 953
56.6.1 交换数据报:recvfrom和sendto() 954
56.6.2 在数据报socket上使用connect() 955
56.7 总结 956
第57章 SOCKET:UNIX DOMAIN 957
57.1 UNIX domain socket地址:struct sockaddr un 957
57.2 UNIX domain中的流socket 959
57.3 UNIX domain中的数据报socket 962
57.4 UNIX domain socket权限 965
57.5 创建互联socket对:socketpair() 965
57.6 Linux抽象socket名空间 966
57.7 总结 967
57.8 习题 967
第58章 SOCKET:TCP/IP网络基础 968
58.1 因特网 968
58.2 联网协议和层 969
58.3 数据链路层 971
58.4 网络层:IP 971
58.5 IP地址 973
58.6 传输层 975
58.6.1 端口号 975
58.6.2 用户数据报协议(UDP) 976
58.6.3 传输控制协议(TCP) 977
58.7 请求注解(RFC) 979
58.8 总结 980
第59章 SOCKET:Internet DOMAIN 982
59.1 Internet domain socket 982
59.2 网络字节序 982
59.3 数据表示 984
59.4 Internet socket地址 986
59.5 主机和服务转换函数概述 988
59.6 inet_pton()和inet_ntop()函数 989
59.7 客户端-服务器示例(数据报socket) 990
59.8 域名系统(DNS) 992
59.9 /etc/services文件 994
59.10 独立于协议的主机和服务转换 995
59.10.1 getaddrinfo()函数 996
59.10.2 释放addrinfo列表:freeaddrinfo() 998
59.10.3 错误诊断:gai_strerror() 999
59.10.4 getnameinfo()函数 999
59.11 客户端-服务器示例(流式socket) 1000
59.12 Internet domain socket库 1006
59.13 过时的主机和服务转换API 1010
59.13.1 inet aton()和inet ntoa()函数 1010
59.13.2 gethostbyname()和gethostbyaddr()函数 1010
59.13.3 getserverbyname()和getserverbyport()函数 1012
59.14 UNIX与Internet domain socket比较 1013
59.15 更多信息 1014
59.16 总结 1014
59.17 习题 1015
第60章 SOCKET:服务器设计 1016
60.1 迭代型和并发型服务器 1016
60.2 迭代型UDP echo服务器 1016
60.3 并发型TCP echo服务器 1019
60.4 并发型服务器的其他设计方案 1021
60.5 inetd(Internet超级服务器)守护进程 1023
60.6 总结 1027
60.7 练习 1027
第61章 SOCKET:高级主题 1028
61.1 流式套接字上的部分读和部分写 1028
61.2 shutdown()系统调用 1030
61.3 专用于套接字的I/O系统调用:recv()和send() 1033
61.4 sendfile()系统调用 1034
61.5 获取套接字地址 1036
61.6 深入探讨TCP协议 1039
61.6.1 TCP报文的格式 1039
61.6.2 TCP序列号和确认机制 1041
61.6.3 TCP协议状态机以及状态迁移图 1041
61.6.4 TCP连接的建立 1043
61.6.5 TCP连接的终止 1044
61.6.6 在TCP套接字上调用shutdown() 1045
61.6.7 TIME_WAIT状态 1045
61.7 监视套接字:netstat 1047
61.8 使用tcpdump来监视TCP流量 1048
61.9 套接字选项 1049
61.10 SO_REUSEADDR套接字选项 1050
61.11 在accept()中继承标记和选项 1051
61.12 TCP vsUDP 1052
61.13 高级功能 1053
61.13.1 带外数据 1053
61.13.2 sendmsg()和recvmsg()系统调用 1053
61.13.3 传递文件描述符 1054
61.13.4 接收发送端的凭据 1054
61.13.5 顺序数据包套接字 1055
61.13.6 SCTP以及DCCP传输层协议 1055
61.14 总结 1056
61.15 练习 1056
第62章 终端 1058
62.1 整体概览 1059
62.2 获取和修改终端属性 1060
62.3 stty命令 1062
62.4 终端特殊字符 1063
62.5 终端标志 1068
62.6 终端的I/O模式 1073
62.6.1 规范模式 1073
62.6.2 非规范模式 1074
62.6.3 加工模式、cbreak模式以及原始模式 1075
62.7 终端线速(比特率) 1081
62.8 终端的行控制 1082
62.9 终端窗口大小 1084
62.10 终端标识 1085
62.11 总结 1086
62.12 练习 1087
第63章 其他备选的I/O模型 1088
63.1 整体概览 1088
63.1.1 水平触发和边缘触发 1091
63.1.2 在备选的I/O模型中采用非阻塞I/O 1092
63.2 I/O多路复用 1092
63.2.1 select()系统调用 1092
63.2.2 poll()系统调用 1097
63.2.3 文件描述符何时就绪? 1101
63.2.4 比较select()和poll() 1103
63.2.5 select()和poll()存在的问题 1105
63.3 信号驱动I/O 1105
63.3.1 何时发送“I/O就绪”信号 1109
63.3.2 优化信号驱动I/O的使用 1110
63.4 epoll编程接口 1113
63.4.1 创建epoll实例:epoll_create() 1113
63.4.2 修改epoll的兴趣列表:epoll_ctl() 1114
63.4.3 事件等待:epoll_wait() 1115
63.4.4 深入探究epoll的语义 1120
63.4.5 epoll同I/O多路复用的性能对比 1121
63.4.6 边缘触发通知 1122
63.5 在信号和文件描述符上等待 1124
63.5.1 pselect()系统调用 1125
63.5.2 self-pipe技巧 1126
63.6 总结 1128
63.7 练习 1129
第64章 伪终端 1130
64.1 整体概览 1130
64.2 UNIX98伪终端 1133
64.2.1 打开未使用的主设备:posix_openpt() 1134
64.2.2 修改从设备属主和权限:grantpt() 1135
64.2.3 解锁从设备:unlockpt() 1135
64.2.4 获取从设备名称:ptsname() 1136
64.3 打开主设备:ptyMasterOpen() 1136
64.4 将进程连接到伪终端:ptyFork() 1138
64.5 伪终端I/O 1140
64.6 实现script(1)程序 1142
64.7 终端属性和窗口大小 1146
64.8 BSD风格的伪终端 1146
64.9 总结 1148
64.10 练习 1149
附录A 跟踪系统调用 1151
附录B 解析命令行选项 1153
附录C 对NULL指针做转型 1159
附录D 内核配置 1161
附录E 更多信息源 1162
附录F 部分习题解答 1167