本书是一部UNIX网络API的经典之作!
本书是为那些希望能够通过套接字接口实现程序间的相互通信的人而编写的,旨在为网络编程的初学者以及专家提供指导。要建立高度分布式、网络化的应用程序和服务,就需要对套接字和其他关键的网络API有深入的理解。本书为在各种环境下建立健壮的、高性能的网络系统提供了全面的指导。
“每个人都会喜欢这本书,因为它提供了大量的实践经验、历史观点以及只有对此领域深入研究才能获得的深刻理解。我在阅读这本书的过程中获得了享受并学到了知识,相信你一定也会的。”
—Sam Leffler
本书是一部UNIX网络API的经典之作!
本书是为那些希望能够通过套接字接口实现程序间的相互通信的人而编写的,旨在为网络编程的初学者以及专家提供指导。要建立高度分布式、网络化的应用程序和服务,就需要对套接字和其他关键的网络API有深入的理解。本书为在各种环境下建立健壮的、高性能的网络系统提供了全面的指导。
这个版本建立在W.Richard Stevens的传奇性工作的基础上,由两个最优秀的网络编程专家进行了完全更新。讨论了当今最关键的标准、实现和技术 讨论的新主题包括:
·POSIX Single UNIX Specification Version 3
·IPv6 APIs(包括更新了的对IPv6/IPv4互操作性的指南)
·新的SCTP传输协议
·基于IPsec的密钥管理套接字
·FreeBSD 4.8/5.1、Red Hat Linux 9.x、Solaris 9、AIX 5.x、HPUX和Max OS X实现
·新的网络编程调试技术
·源端特定的组播API,正是这个API使得IP组播开发被广泛使用
本书还更新和扩展了Stevens对以下关键的UNIX网络标准和技术所做的权威性的概括:
·TCP和UDP传输
·基本的和高级的套接宇,路由的和原始的套接宇
·I/O:复用高级函数,非阻塞和信号驱动
·守护进程和inetd
·UNIX域协议
·ioctl操作
·广播和组播
·线程
·流
·设计:TCP迭代的、并发的、预先创建的和预先线程化的服务器
作者 W.Richard Stevens 生前力作:
《UNIX网络编程(卷1):连网的APLs:套接字与XTI(第二版)(英文影印版)》
《UNIX网络编程(卷2):进程间通信(第二版)(英文影印版)》
Part1. Introduction and TCP/IP
Chapter1. Introduction
1.1 Introduction 3
1.2 A Simple Daytime Client 6
1.3 Protocol Independence 10
1.4 Error Handling: Wrapper Functions 11
1.5 A Simple Daytime Server 13
1.6 Roadmap to Client/Server Examples in the Text 16
1.7 OSI Model !8
1.8 BSD Networking History 20
1.9 Test Networks and Hosts 22
1.10 Unix Standards 25
1.11 64-Bit Architectures 28
1.12 Summary 29
Chapter 2. The Transport Layer: TCP, UDP, and SCTP
2.1 Introduction 31
2.2 The Big Picture 32
2.3 User Datagram Protocol (UDP) 34
2.4 Transmission Control Protocol (TCP) 35
2.5 Stream Control Transmission Protocol (SCTP) 36
2.6 TCP Connection Establishment and Termination 37
2.7 TIME_WAIT State 43
2.8 SCTP Association Establishment and Termination 44
2.9 Port Numbers 50
2.10 TCP Port Numbers and Concurrent Servers 52
2.11 Buffer Sizes and Limitations 55
2.12 Standard Internet Services 61
2.13 Protocol Usage by Common Internet Applications 62
2.14 Summary 63
Part 2. Elementary Sockets
Chapter 3. Sockets Introduction
3.1 Introduction 67
3.2 Socket Address Structures 67
3.3 Value-Result Arguments 74
3.4 Byte Ordering Functions 77
3.5 Byte Manipulation Functions 80
3.6 inet_aton, inet_addr, and inet_ntoa Functions 82
3.7 inet_pton and inet_ntop Functions 83
3.8 sock_ntop and Related Functions 86
3.9 readn, writen, and readline Functions 88
3.10 Summary 92
Chapter 4. Elementary TCP Sockets
4.1 Introduction 9,5
4.2 socket Function 95
4.3 connect Function 99
4.4 bind Function 101
4.5 listen Function 104
4.6 accept Function 109
4.7 fork and exec Functions 111
4.8 Concurrent Servers 114
4.9 close Function 117
4.10 getsockname and getpeername Functions 117
4.11 Summary 120
Chapter 5, TCP Client/Server Example
5.1 Introduction 121
5.2 TCP Echo Server: main Function 122
5.3 TCP Echo Server: str echo Function 123
5.4 TCP Echo Client: main Function 124
5.5 TCP Echo Client: str cli Function 125
5.6 Normal Startup 126
5.7 Normal Termination 128
5.8 POSIX Signal Handling 129
5.9 Handling SIGCHLD Signals 132
5.10 wait and waitpid Functions 135
5.11 Connection,Abort before accept Returns 139
5.12 Termination of Server Process 141
5.13 SIGPIPE Signal 142
5.14 Crashing of Server Host 144
5.15 Crashing and Rebooting of Server Host 144
5.16 Shutdown of Server Host 145
5.17 Summary of TCP Example 146
5.18 Data Format 147
5.19 Summary 151
Chapter 6. I/O Multiplexing: The select and poll Functions
6.1 Introduction 153
6.2 I/O Models 154
6,3 select Function 160
6.4 str_cli Function (Revisited) 167
6.5 Batch Input and Buffering 169
6.6 shutdown Function 172
6.7 str eli Function (Revisited Again) 173
6.8 TCP Echo Server (Revisited) 175
6.9 pselect Function 181
6.10 poll Function 182
6.11 TCP Echo Server (Revisited Again) 185
6.12 Summary 188
Chapter 7. Socket Options
7.1 Introduction 191
7.2 getsockopt and setsockopt Functions 192
7.3 Checking if an Option Is Supported and Obtaining the Default
7.4 Socket States 198
7.5 Generic Socket Options 198
7.6 IPv4 Socket Options 214
7.7 ICMPv6 Socket Option 216
7.8 IPv6 Socket Options 216
7.9 TCP Socket Options 219
7.10 SCTP Socket Options 222
7.11 fcnt1 Function 233
7.12 Summary 236
Chapter 8. Elementary UDP Sockets
8.1 Introduction 239
8.2 recvfrom and sendto Functions 240
8.3 UDP Echo Server: main Function 241
8.4 UDP Echo Server: dg_echo Function 242
8.5 UDP Echo Client: main Function 244
8.6 UDP Echo Client: dg_cli Function 245
8.7 Lost Datagrams 245
8.8 Verifying Received Response 246
8.9 Server Not Running 248
8.10 Summary of UDP Example 250
8.11 connect Function with UDP 252
8.12 dg_cli Function (Revisited) 256
8,13 Lack of Flow Control with UDP 257
8.14 Determining Outgoing Interface with UDP 261
8.15 TCP and UDP Echo Server Using select 262
8.16 Summary 264
Chapter 9. Elementary SCTP Sockets
9.1 Introduction 267
9.2 Interface Models 268
9.3 sctp_bindx Function 272
9.4 sctp_connectx Function 274
9.5 sctp_getpaddrs Function 275
9.6 sctp_freepaddrs Function 275
9.7 sctp_get laddrs Function 275
9.8 sctp_freeladdrs Function 276
9.9 sctp_sendmsg Function 276
9.10 sctp_recvmsg Function 277
9.11 sctp_opt_info Function 278
9.12 sctp_peeloff Function 278
9.13 shutdown Function 278
9.14 Notifications 280
9.15 Summary 286
Chapter10. SCTP Client/Server Example
10.1 Introduction 287
10.2 SCTP One-to-Many-Style Streaming Echo Server: main Function
10.3 SCTP One-to-Many-Style Streaming Echo Client: main Function
10.4 SCTP Streaming Echo Client: str_cli Function 292
10.5 Exploring Head-of-Line Blocking 293
10.6 Controlling the Number of Streams 299
10.7 Controlling Termination 300
10.8 Summary 301
Chapter11. Name and Address Conversions
11.1 Introduction 303
11.2 Domain Name System (DNS) 303
11.3 gethostbyname Function 307
11.4 gethostbyaddr Function 310
11.5 getservbyname and getservbyport Functions 311
11.6 getaddrinfo Function 315
11.7 gai_strerror Function 320
11.8 freeaddrinfo Function 321
11.9 getaddrinfo Function: IPv6 322
11.10 getaddrinfo Function: Examples 324
11.11 host serv Function 325
11.12 tcp_connect Function 326
11.13 tcp_listen Function 330
11.14 udp_client Function 334
11.15 udp_connect Function 337
11.16 udp_server Function 338
11.17 getnameinfo Function 340
11.18 Re-entrant Functions 341
11.19 gethostbyname_r and gethostbyaddr_r Functions 344
11.20 Obsolete IPv6 Address Lookup Functions 346
11.21 Other Networking Information 348
11.22 Summary 349
Part 3. Advanced Sockets
Chapter12. IPv4 and IPv6 Interoperability
12.1 Introduction 353
12.2 IPv4 Client, IPv6 Server 354
12.3 IPv6 Client, IPv4 Server 357
12.4 IPv6 Address-Testing Macros 360
12.5 Source Code Portability 361
12.6 Summary 362
Chapter13. Daemon Processes and the inetd Superserver
13.1 Introduction 363
13.2 syslogd Daemon 364
13.3 syslo9 Function 365
13.4 daemon init Function 367
13.5 inetd Daemon 371
13.6 daemon inetd Function 377
13.7 Summary 379
Chapter14. Advanced I/O Functions
14.1 Introduction 381
14,2 Socket Timeouts 381
14.3 recv and send Functions 387
14.4 readv and writev Functions 389
14.5 recvmsg and sendmsg Functions 390
14,6 Ancillary Data 395
14.7 How Much Data Is Queued? 398
14.8 Sockets and Standard I/O 399
14.9 Advanced Polling 402
14.10 Summary 408
Chapter15. Unix Domain Protocols 411
15.1 Introduction 411
15.2 Unix Domain Socket Address Structure 412
15.3 socketpair Function 414
15.4 Socket Functions 415
15.5 Unix Domain Stream Client/Server 416
15.6 Unix Domain Datagram Client/Server 418
15.7 Passing Descriptors 420
15.8 Receiving Sender Credentials 429
15.9 Summary 432
Chapter16. Nonblocking I/O 435
16.1 Introduction 435
16.2 Nonblocking Reads and Writes: str cli Function (Revisited) 437
16.3 Nonblocking connect 448
16.4 Nonblocking connect: Daytime Client 449
16.5 Nonblocking connect: Web Client 452
16.6 Nonblocking accept 461
16.7 Summary 463
Chapter17. ioct1 Operations 465
17.1 Introduction 465
17.2 ioctl Function 466
17.3 Socket Operations 466
17.4 File Operations 468
17.5 Interface Configuration 468
17.6 get ifi info Function 469
17.7 Interface Dperations 480
17.8 ARP Cache Operations 481
17.9 Routing Table Operations 483
17.10 Summary 484
Chapter18. Routing Sockets 485
18.1 Introduction 485
18.2 Datalink Socket Address Structure 486
18.3 Reading and Writing 487
18.4 sysctl Operations 495
18.5 get_ifi_info Function (Revisited) 500
18.6 Interface Name and Index Functions 504
18.7 Summary 508
Chapter19. Key Management Sockets511
19.1 Introduction 511
19.2 Reading and Writing 512
19.3 Dumping the Security Association Database (SADB) 514
19.4 Creating a Static Security Association (SA) 517
19.5 Dynamically Maintaining SAs 524
19.6 Summary 528
Chapter 20. Broadcasting 529
20.1 Introduction 529
20.2 Broadcast Addresses 531
20.3 Unicast versus Broadcast 532
20.4 dg_cli Function Using Broadcasting 535
20.5 Race Conditions 538
20.6 Summary 547
Chapter 21. Multicasting 549
21.1 Introduction 549
21.2 Multicast Addresses 549
21.3 Multicasting versus Broadcasting on a LAN 553
21.4 Multicasting on a WAN 556
21.5 Source-Specific Multicast 558
21.6 Multicast Socket Options 559
21.7 mcast_join and Related Functions 565
21.8 dg_cli Function Using Multicasting 570
21.9 Receiving IP Multicast Infrastructure Session Announcements 571
21.10 Sending and Receiving 575
21.11 Simple Network Time Protocol (SNTP) 579
21.12 Summary 584
Chapter 22. Advanced UDP Sockets 587
22.1 Introduction 587
22.2 Receiving Flags, Destination IP Address, and Interface Index 588
22.3 Datagram Truncation 594
22.4 When to Use UDP Instead of TCP 594
22.5 Adding Reliability to a UDP Application 597
22.6 Binding Interface Addresses 608
22.7 Concurrent UDP Servers 612
22.8 IPv6 Packet Information 615
22.9 IPv6 Path MTU Control 618
22.10 Summary 620
Chapter 23. Advanced SCTP Sockets 621
23.1 Introduction 621
23.2 An Autoclosing One-to-Many-Style Server 621
23.3 Partial Delivery 622
23.4 Notifications 625
23.5 Unordered Data 629
23.6 Binding a Subset of Addresses 630
23.7 Determining Peer and Local Address Information 631
23.8 Finding an Association ID Given an IP Address 635
23.9 Heartbeating and Address Failure 636
23.10 Peeling Off an Association 637
23.11 Controlling Timing 639
23.12 When to Use SCTP Instead of TCP 641
23.13 Summary 643
Chapter 24. Out-of-Band Data 645
24.1 Introduction 645
24.2 TCP Out-of-Band Data 645
24.3 sockatmark Function 654
24.4 TCP Out-of-Band Data Recap 661
24.5 Summary 662
Chapter 25. Signal-Driven I/O663
25.1 introduction 663
25.2 Signal-Driven I/O for Sockets 664
25.3 UDP Echo Server Using SIGIO 666
25.4 Summary 672
Chapter 26. Threads 675
26.1 Introduction 675
26.2 Basic Thread Functions: Creation and Termination 676
26.3 str cli Function Using Threads 679
26.4 TcP-Echo Server Using Threads 681
26.5 Thread-Specific Data 686
26.6 Web Client and Simultaneous Connections (Continued) 694
26.7 Mutexes: Mutual Exclusion 697
26.8 Condition Variables 701
26.9 Web Client and Simultaneous Connections (Continued) 705
26.10 Summary 707
Chapter 27. IP Options 709
27.1 Introduction 709
27.2 IPv4 Options 709
27.3 IPv4 Source Route Options 711
27.4 I Pv6 Extension Headers 719
27.5 IPv6 Hop-by-Hop Options and Destination Options 719
27.6 IPv6 Routing Header 725
27.7 IPv6 Sticky Options 731
27.8 Historical IPv6 Advanced API 732
27.9 Summary 733
Chapter 28. Raw Sockets 735
28.1 introduction 735
28.2 Raw Socket Creation 736
28.3 Raw Socket Output 737
28.4 Raw Socket Input 739
28.5 ping Program 741
28.6 traceroute Program 755
28.7 An ICMP Message Daemon 769
28.8 Summary 786
Chapter 29. Datalink Access 787
29.1 Introduction 787
29.2 BSD Packet Filter (BPF) 788
29.3 Datalink Provider Interface (DLPI) 790
29.4 Linux: SOCK' PACKET and PF PACKET 791
29.5 libpcap: Packet Capture Library 792
29.6 libnet: Packet Creation and Injection Library 793
29.7 Examining the UDP Checksum Field 793
29.8 Summary 815
Chapter 30. Client/Server Design Alternatives 817
30.1 Introduction 817
30.2 TCP Client Alternatives 819
30.3 TCP Test Client 820
30.4 TCP Iterative Server 821
30.5 TCP Concurrent Server, One Child per Client 822
30.6 TCP Preforked Server, No Locking Around accept 826
30.7 TCP Preforked Server, File Locking Around accept 832
30.8 TCP Preforked Server, Thread Locking Around accept 835
30.9 TCP Preforked Server, Descriptor Passing 836
30.10 TCP Concurrent Server, One Thread per Client 842
30.11 TCP Prethreaded Server, per-Thread accept 844
30.12 TCP Prethreaded Server, Main Thread accept 846
30.13 Summary 849
Chapter 31. STREAMS 851
31.1 Introduction 851
31.2 Overview 851
31.3 getmsg and putmsg Functions 856
31.4 getpmsg and putpmsg Functions 857
31.5 ioctl Function 857
31.6 Transport Provider Interface (TPI) 858
31.7 Summary 868
Appendix A. IPv4, IPv6, ICMPv4, and ICMPv6 869
A.1 Introduction 869
A.2 IPv4 Header 869
A.3 IPv6 Header 871
A.4 IPv4 Addresses 874
A.5 IPv6 Addresses 877
A.6 Internet Control Message Protocols (ICMPv4 and ICMPv6) 882
Appendix B. Virtual Networks 885
B.1 Introduction 885
B.2 The MBone 885
B.3 The 6bone 887
B.4 IPv6 Transition: 6to4 889
Appendix C. Debugging Techniques 891
C.1 System Call Tracing 891
C.2 Standard Internet Services 893
0.3 sock Program 893
C.4 Small Test Programs 896
C.5 tcpdump Program 896
C.6 netstat Program 896
C.7 lsof Program 897
Appendix D. Miscellaneous Source Code 899
D.1 unp.h Header 899
D.2 config, h Header 904
D.3 Standard Error Functions 910
Appendix E. Solutions to Selected Exercises 913
Bibliography 947
Index 955
已故的W.Richard Stevens是本书第1版和第2版的最初作者.
Bill Fenner是位于加州Menlo Park的AT&T实验室的主要技术成员, 专门从事IP组播. 网络管理和测量方面的研究. 他是IETF路由领域的主管之一, 负责审批作为RFC发布的所有与路由有关的文档.
Andrew M. Rudoff是Sun公司的资深软件工程师, 专门从事网络. 操作系统内核. 文件系统及高可靠性软件结构的研究.
Introduction
This book is for people who want to write programs that communicate with each other using an application program interface (API) known as sockets. Some readers may be very familiar with sockets already, as that model has become synonymous with network programming. Others may need an introduction to sockets from the ground up. The goal of this book is to offer guidance on network programming for beginners as well as professionals, for those developing new network-aware applications as well as those maintaining existing code, and for people who simply want to understand how the net- working components of their system function.
All the examples in this text are actual, runnable code tested on Unix systems. However, many non-Unix systems support the sockets API and the examples are largely operating system-independent, as are the general concepts we present. Virtually every operating system (OS) provides numerous network-aware applications such as Web browsers, email clients, and file-sharing servers. We discuss the usual partitioning of these applications into client and server and write our own small examples of these many times throughout the text.
Presenting this material in a Unix-oriented fashion has the natural side effect of pro-viding background on Unix itself, and on TCP/IP as well. Where more extensive back-ground may be interesting, we refer the reader to other texts. Four texts are so com-monly mentioned in this book that we've assigned them the following abbreviations:
· APUE: Advanced Programming in the UNIX Environment [Stevens 1992]
· TCPv1: TCP//P Illustrated, Volume 1 [Stevens 1994]
· TCPv2: TCP//P Illustrated, Volume 2 [Wright and Stevens 1995]
· TCPv3: TCP//P Illustrated, Volume 3 [Stevens 1996]
TCPv2 contains a high level of detail very closely related to the material in this book, as it describes and presents the actual 4.4BSD implementation of the network program-ming functions for the sockets API (socket, bind, connect, and so on). If one under-stands the implementation of a feature, the use of that feature in an application makes more sense.
Changes from the Second Edition
Sockets have been around, more or less in their current form, since the 1980s, and it is a tribute to their initial design that they have continued to be the network APl of choice. Therefore, it may come as a surprise to learn that quite a bit has changed since the sec- ond edition of this book was published in 1998. The changes we've made to the text are summarized as follows:
· This new edition contains updated information on IPv6, which was only in draft form at the time of publication of the second edition and has evolved somewhat.
· The descriptions of functions and the examples have all been updated to reflect the most recent POSIX specification (POSIX 1003.1-2001), also known as the Single Unix Specification Version 3.
· The coverage of the X/Open Transport Interface (XTI) has been dropped. That API has fallen out of common use and even the most recent POSIX specification does not bother to cover it.
· The coverage of TCP for transactions (T/TCP) has been dropped.
· Three chapters have been added to describe a relatively new transport protocol, SCTE This reliable, message-oriented protocol provides multiple streams between endpoints and transport-level support for multihoming. It was origi-nally designed for transport of telephony signaling across the Intemet, but pro-vides some features that many applications could take advantage of.
· A chapter has been added on key management sockets, which may be used with Intemet Protocol Security (IPsec) and other network security services.
· The machines used, as well as the versions of their variants of Unix, have all been updated, and the examples have been updated to reflect how these machines behave. In many cases, examples were updated because OS vendors fixed bugs or added features, but as one might expect, we've discovered the occasional new bug here and there. The machines used for testing the examples in this book were:
· Apple Power PC running MacOS/X 10.2.6
· HP PA-RISC running HP-UX lli
· IBM Power PC running AIX 5.1
· Intel x86 running FreeBSD 4.8
· Intel x86 running Linux 2.4.7
· Sun SPARC running FreeBSD 5.1
· Sun SPARC running Solaris 9
See Figure 1.16 for details on how these machines were used. Volume 2 of this UNIX Network Programming series, subtitled Interprocess Communi-cations, builds on the material presented here to cover message passing, synchroniza-tion, shared memory, and remote procedure calls.
.Using This Book
This text can be used as either a tutorial on network programming or as a reference for experienced programmers. When used as a tutorial or for an introductory class on net-work programming, the emphasis should be on Part 2, "Elementary Sockets" (Chapters 3 through 11), followed by whatever additional topics are of interest. Part 2 covers the basic socket functions for both TCP and UDP, along with SCTP, I/O multiplexing, socket options, and basic name and address conversions. Chapter 1 should be read by all readers, especially Section 1.4, which describes some wrapper functions used throughout the text. Chapter 2 and perhaps Appendix A should be referred to as neces-sary, depending on the reader's background. Most of the chapters in Part 3, "Advanced Sockets," can be read independently of the others in that part of the book.
To aid in the use of this book as a reference, a thorough index is provided, along with summaries on the end papers of where to find detailed descriptions of all the func-tions and structures. To help those reading topics in a random order, numerous refer-ences to related topics are provided throughout the text.
Source Code and Errata Availability
The source code for all the examples that appear in the book is available on the Web at www. unpbook, com. The best way to learn network programming is to take these pro-grams, modify them, and enhance them. Actually writing code of this form is the only way to reinforce the concepts and techniques. Numerous exercises are also provided at the end of each chapter, and most answers are provided in Appendix E.
A current errata for the book is also available from the same Web site.
Acknowledgments
The first and second editions of this book were written solely by W. Richard Stevens, who passed away on September 1, 1999. His books have set a high standard and are largely regarded as concise, laboriously detailed, and extremely readable works of art. In providing this revision, the authors struggled to maintain the quality and thorough coverage of Rich's earlier editions and any shortcomings in this area are entirely the fault of the new authors.
The work of an author is only as good as the support from family members and friends. Bill Fenner would like to thank his dear wife, Peggy (beach 1 4 mile champion), and their housemate, Christopher Boyd for letting him off all his household chores while working in the treehouse on this project. Thanks are also due to his friend, Jerry Winner, whose prodding and encouragement were invaluable. Likewise, Andy Rudoff wants to specifically thank his wife, Ellen, and girls, Jo and Katie, for their understand-lng and encouragement throughout this project. We simply could not have done this without all of you.
Randall Stewart with Cisco Systems, Inc. provided much of the SCTP material and deserves a special acknowledgment for this much-valued contribution. The coverage of this new and interesting topic simply would not exist without Randall's work. The feedback from our reviewers was invaluable for catching errors, pointing out areas that required more explanation, and suggesting improvements to our text and code examples. The authors would like to thank: James Carlson, Wu-Chang Feng, Rick
Jones, Brian Kemighan, Sam Leffier, John McCann, Craig Metz, Ian Lance Taylor, David Schwartz, and Gary Wright.
Numerous individuals and their organizations went beyond the normal call of duty to provide either a loaner system, software, or access to a system, all of which were used to test some of the examples in the text.
Jessie Haug of IBM Austin provided an AIX system and compilers.
Rick Jones and William Gilliam of Hewlett-Packard provided access to multiple systems running HP-UX.
The staff at Addison Wesley has been a true pleasure to work with: Noreen Regina, Kathleen Caren, Dan DePasquale, Anthony Gemellaro, and a very special thanks to our editor, Mary Franz.
In a trend that Rich Stevens instituted (but contrary to popular fads), we produced camera-ready copy of the book using the wonderful Groff package written by James Clark, created the illustrations using the gpic program (using many of Gary Wright's macros), produced the tables using the gtbl program, performed all the indexing, and did the final page layout. Dave Hanson's loom program and some scripts by Gary Wright were used to include the source code in the book. A set of awk scripts written by Jon Bentley and Brian Kernighan helped in producing the final index.
The authors welcome electronic mail from any readers with comments, suggestions, or bug fixes.
Bill Fenner Andrew M. Rudoff
Woodside, California Boulder, Colorado
October 2003
authors@unpbook, com
http: //www. unpbook, com