【UNIX环境高级编程】标准IO库详解

本文详细解析了标准IO库在流和FILE对象、缓冲机制、打开流、读写操作、二进制I/O、定位流、格式化I/O以及临时文件等方面的关键概念和函数,帮助读者掌握在UNIX环境中进行高级编程的技术细节。
摘要由CSDN通过智能技术生成

流和FILE对象

对于标准I/O库,它们的操作都是围绕流(stream)进行的,当用标准I/O库打开或创建一个文件时,我们已使一个流与一个文件相关联。

当一个流最初被创建时,它并没有定向,如果在未定向的流上使用一个多字节I/O函数,则将该流的定向设置为宽定向的。如果在未定向的流上使用一个单字节I/O函数,则将该流的定向设置为字节定向的。

freopen函数清除一个流的定向。

fwide函数设置流的定向。

fwide

如何流式宽定向的则返回正值,若流式字节定向的则返回负值,若流未定向返回0。

mode参数值为负:fwide将试图使指定的流是字节定向的。

mode参数值为正:fwide将试图使指定的流是宽定向的。

mode参数值为0:fwide将不试图设置流的定向,但返回标识该流定向的值。

#include <wchar.h>

int fwide(FILE *stream, int mode);

缓冲

标准I/O库提供缓冲的目的是尽可能减少使用read和write调用的次数,它也对每个I/O流自动地进行缓冲管理,从而避免了应用程序需要考虑这一点所带来的麻烦。

全缓冲

这种情况下,在填满标准I/O缓冲区后才进行实际I/O操作,对于驻留在磁盘上的文件通常是由标准I/O库实施全缓冲的。在一个流上执行第一次I/O操作时,相关标准I/O函数通常调用malloc获得需使用的缓冲区。

冲洗(flush)说明标准I/O库的写操作,缓冲区可由标准I/O例程自动冲洗,或者可以调用函数fflush冲洗一个流。值得引起注意的是在UNIX环境下,flush有两种意思,在标准I/O库方面,flush意味着将缓冲区中的内容写到磁盘上,在终端驱动程序方面,flush表示丢弃已存储在缓冲区中的数据。

行缓冲

在这种情况下,当在输入和输出中遇到换行符时,标准I/O库执行I/O操作,这允许我们一次输出一个字符,但只有在写了一行之后才进行实际I/O操作,当流涉及一个终端时,通常使用行缓冲。

不带缓冲

标准I/O库不对字符进行缓冲存储。

标准出错流stderr通常是不带缓冲的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个换行符。

很多系统默认使用下列类型的缓冲:

  • 标准出错是不带缓冲的;
  • 如果是涉及终端设备的其他流,则它们是行缓冲的,否则是全缓冲的。

如果想要更改缓冲类型可以通过下面两个方法。如果成功返回0,失败返回非0。

#include <stdio.h>

void setbuf(FILE *stream, char *buf);

int setvbuf(FILE *stream, char *buf, int mode, size_t size);

可以使用setbuf函数打开或关闭缓冲机制,为了带缓冲进行I/O操作,参数buf必须指向一个长度为BUFSIZ的缓冲区(该常量在stdio.h中定义),通常在此之后该流就是全缓冲的,但是如果该流与一个终端设备相关,那么某些系统也可以将其设置为行缓冲。为了关闭缓冲,将buf设置为NULL。

使用setvbuf我们可以精确的指定所需的缓冲类型,mode常量(该常量在stdio.h中定义)。

  • _IOFBF:全缓冲
  • _IOLBF:行缓冲
  • _IONBF:不带缓冲

使用fflush函数来强制冲洗一个流。

flush有两种意思

  • 在标准I/O库方面,flush意味着将缓冲区中的内容写到磁盘上;‘
  • 在终端驱动程序方面,flush表示丢弃已存储在缓冲区中的数据。
#include <stdio.h>

int fflush(FILE *stream);

打开流

#include <stdio.h>
//打开文件,并返回文件指针
FILE *fopen(const char *pathname, const char *mode);
//打开文件,并返回文件指针
FILE *fdopen(int fd, const char *mode);
//清除一个流的定向
FILE *freopen(const char *pathname, const char *mode, FILE *stream);
  • fopen打开一个指定的文件;
  • freopen在一个指定的流上打开一个指定的文件,若该流已经打开,则先关闭该流。若该流已经定向,则freopen清除该定向。此函数一般用于将一个指定的文件打开为一个预定义的流,标准输入、标准输出或标准出错。
  • fdopen获取一个现有的文件描述符,并使一个标准I/O流与该描述符相结合。此函数常用于创建管道和网络通信管道函数返回的描述符。因为这些特殊类型的文件不能用标准I/Ofopen函数打开。

打开标准I/O流的mode参数

  • r或rb:为读而打开
  • w或wb:将文件截短至0长,或为写而创建
  • a或ab:添加,为在文件尾写而打开,或为写而创建
  • r+或r+b或rb+:为读和写而打开
  • w+或w+b或wb+:把文件截短至0长,或为读和写而打开
  • a+或a+b或ab+:为在文件尾读和写而打开或创建
// 打开文件,并返回文件指针
FILE *fp = fopen(F_PATH, "r");

调用close关闭一个打开的流。

#include <unistd.h>

int close(int fd);

在该文件被关闭之前,冲洗缓冲区中的输出数据,丢弃缓冲区中的任何输入数据,如果标准I/O库已经为该流自动分配了一个缓冲区,则释放此缓冲区。

当一个进程正常终止时,则所有带未写缓冲数据的标准I/O都会被冲洗,所有打开的标准I/O都会被关闭。

读和写流

每次一个字符I/O

输入函数

下面三个函数可用于一次读一个字符。若成功返回下一个字符,若已到达文件结尾或出错则返回EOF(-1)。

这三个函数返回下一个字符的时候,会将unsigned char类型转换为int类型。

#include <stdio.h>

int fgetc(FILE *stream);

int getc(FILE *stream);

int getchar(void);

getc可被实现为宏,fgetc则不能实现为宏。

getc的参数不应当时具有副作用的表达式。

因为fgetc一定是一个函数,所以可以得到其地址,这就允许将fgetc的地址作为一个参数传送给另一个函数。

调用fgetc所需的时间很可能长于调用getc,因为函数调用所需的时间通常长于调用宏的时间。

不管是出错还是到达文件尾端,这三个函数都返回同样的值,为了区分这两种不同的情况,必须调用ferror或feof函数;

ferror和feof函数返回值,若条件为真则返回非0值,若条件为假,返回0。

#include <stdio.h>

void clearerr(FILE *stream);
//
int feof(FILE *stream);

int ferror(FILE *stream);

代码示例

#include<stdio.h>
int main(void)
{
    FILE *p;
    p = fopen("open.txt", "r");
    getc(p);
    if (feof(p))
    {
        printf("文件为空。");
    }
    else
    {
        rewind(p);//将光标跳回到文件开头
        int a;
        fscanf(p,"%d",&a);
        printf("%d", a);
    }
    return 0;
 }

输出函数

每个输入函数都有一个输出函数。与输入函数一样,putchar©等效于putc(c,stdout),putc可实现为宏,而fputc不能实现为宏。

#include <stdio.h>

int fputc(int c, FILE *stream);

int putc(int c, FILE *stream);

int putchar(int c);

每次一行I/O

输入函数

下面两个函数提供每次输入一行的功能,成功返回buf,若已达到文件结尾或者出错则返回NULL。

#include <stdio.h>

char *gets(char *s);
//size 读取的字节数,实际上读取的字节数为size-1
char *fgets(char *s, int size, FILE *stream);

不推荐使用gets,因为它不能指定缓冲区的长度,容易造成缓冲区溢出。

fgets必须指定缓冲区的长度size,此函数一直读到下一个换行符为止,但是不超过size-1,读入的字符被送入缓冲区,该缓冲区以null字符结尾。如果该行的字符数超过size-1,则fgets只返回一个不完整的行,但是缓冲区总是以null字符结尾。,对fgets的下一次调用会继续读该行。

输出函数

#include <stdio.h>

int fputs(const char *s, FILE *stream);

int puts(const char *s);

fputs将一个以null符终止的字符串写到指定的流,尾端的终止符null不写出。这并不一定是每次输出一行,因为它并不要求在null符之前一定是换行符,通常在null符之前是一个换行符,但并不要求总是如此。

puts将一个以null符终止的字符串写到标准输出,终止符不写出,但是puts然后又将一个换行符写到标准输出。

代码示例

#include <stdio.h>
#define MAXLINE 4096
void main(int argc, char *argv[])
{

    char buf[MAXLINE];

    while (fgets(buf, MAXLINE, stdin) != NULL)
    {
        if (fputs(buf, stdout) == EOF)
        {
            printf("output error");
        }
    }
    if (ferror(stdin))
    {
        printf("input error");
    }
	return;
}

二进制I/O

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

常见用法

  1. 读或写一个二进制数组,size为每个数组元素的长度,nmemb为要写的元素数。
  2. 读或写一个结构,size为结构的长度,nmemb为要写的对象数
#include <stdio.h>
struct
{
    short count;
    long total;
    char name[100];

} item;

void main(int argc, char *argv[])
{

    float data[10];
    FILE *fp = open("open.txt", "r");
	//写一个二进制数组
    if (fwrite(&data[2], sizeof(float), 4, fp) != 4)
    {
        printf("error");
    }
	//写一个结构
    if (fwrite(&item, sizeof(item), 1, fp) != 1)
    {
        printf("error");
    }

    return;
}

二进制I/O的基本问题是,它只能用于读在同一个系统上已写的数据,很多异构系统通过网络相互连接,常常在一个系统上写的数据,要在另一个系统上进行处理,在这种情况下两个函数可能就不能正常工作。

  • 在一个结构中,同一成员的偏移量可能因编译器和系统而异。
  • 用来存储多字节整数和浮点值的二进制格式在不同的机器体系结构间也可能不同。

定位流

#include <stdio.h>
//成功返回0,出错返回非0值
int fseek(FILE *stream, long offset, int whence);
//若成功返回当前文件位置指示,出错返回-1L
long ftell(FILE *stream);
//将一个流设置到文件的起始为止
void rewind(FILE *stream);

ftell用于二进制文件时,其返回值就是这种字节位置。

fseek必须指定一个字节offset以及解释这种偏移量的方式。

  • 若whence是SEEK_SET(0),则将该文件的偏移量设置为距文件开始处offset个字节;
  • 若whence是SEEK_CUR(1),则将该文件的偏移量设置为其当前值加offset,offset可正可负;
  • 若whence是SEEK_END(2),则将该文件的偏移量设置为文件长度加offset,offset可正可负;

为了定位一个文本文件,whence一定要是SEEK_SET,而且offset只能有两种值0或者对该文件调用ftell所返回的值。

ftello函数与ftell相同,fseeko与fseek相同。

#include <stdio.h>
//成功返回0,出错返回非0
int fseeko(FILE *stream, off_t offset, int whence);
//成功返回当前文件位置指示,出错返回-1
off_t ftello(FILE *stream);

fgetpos将文件位置指示器的当前值存入由pos指向的对象中,在以后调用fsetpos时,可以使用此值将流重新定位至该位置。成功返回0,失败返回非0。

#include <stdio.h>
   
int fgetpos(FILE *stream, fpos_t *pos);

int fsetpos(FILE *stream, const fpos_t *pos);

格式化I/O

格式化输出

printf、fprintf成功返回输出字符数,输出错误返回负值。

sprintf、snprintf成功则返回存入数组str的字符数,编码出错则返回负值。

#include <stdio.h>
//将格式化数据写到标准输出
int printf(const char *format, ...);
//写至指定的流
int fprintf(FILE *stream, const char *format, ...);  
//将格式化的字符送入数组str中
int sprintf(char *str, const char *format, ...);
//在该数组的尾端自动加一个null字节,但该字节不包括在返回值中
int snprintf(char *str, size_t size, const char *format, ...);

sprintf可能会造成由str指向的缓冲区的溢出,从而引出了snprintf函数,将缓冲区长度作为一个显示参数。

格式说明控制参数编写

%[flags][fldwidth][precision][lenmodifier]convtype

flags

  • -:在字段内左对齐输出
  • +:总是显示带符号转换的符号
  • 空格:如果第一个字符不是符号,则在其前面加上一个空格
  • #:指定另一中转换形式,例如十六进制 加0x前缀
  • 0:添加前导0进行填充

fldwidth
说明转换的最小字段宽度,如果转换得到的字符较少,则用空格填充。

precision
说明整型转换后最少输出数字位数、浮点转换后小数点后的最少位数、字符串转换后的最大字符数。精度是一个句点(.),后接一个可选的非负十进制数或一个星号(*)。

lenmodifier

  • hh:有符号或无符号的char
  • h:有符号或无符号的short
  • l:有符号或无符号的long或宽字符
  • ll:有符号或无符号的long long
  • j:intmax_*t或uintmax_*t
  • z:size_t
  • t:ptrdiff_t
  • L:long double

convtype不是可选的

  • d、i:无符号十进制
  • o:无符号八进制
  • u:无符号十进制
  • x、X:无符号十六进制
  • f、F:double精度浮点数
  • e、E:指数格式的double精度浮点数
  • g、G:解释为f、F、e、E取决于被转换的值
  • a、A:十六进制指数格式的double精度浮点数
  • c:字符
  • s:字符串
  • p:指向void的指针
  • n:将到目前为止,所写的字符数写入到指针
  • %:%字符
  • C:宽字符
  • S:宽字符

可变参数表换成了arg

#include <stdarg.h>

int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);

int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

格式化输入

三个函数的返回值,指定的输入项数,若输入出错或在任意变换前已到达文件结尾则返回EOF。

#include <stdio.h>

int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);

scanf族用于分析输入字符串,并将字符序列转换成指定类型的变量,格式之后的各参数包含了变量的地址,以用转换结果初始化这些变量。

与printf族一样,scanf也支持函数使用由<stdarg.h>说明的可变参数表。

#include <stdarg.h>

int vscanf(const char *format, va_list ap);
int vsscanf(const char *str, const char *format, va_list ap);
int vfscanf(FILE *stream, const char *format, va_list ap);

临时文件

标准I/O库提供了两个函数以帮助创建临时文件。

#include <stdio.h>
//返回指向唯一路径名的指针
char *tmpnam(char *s);
//若成功返回文件指针,失败返回NULL
FILE *tmpfile(void);

tmpnam函数产生一个与现有文件名不同的一个有效路径名字符串,每次调用它时,它都产生一个不同的路径名,最多调用次数是TMP_MAX(在<stdio.h>中定义)。

tempnam是tmpnam的一个变体,它允许调用者为所产生的路径名指定目录和前缀。

  • 如果定义了环境变量TMPDIR,则用其作为目录
  • 如果参数directory非NULL,则用其作为目录
  • 将<stdio.h>中的字符串P_tmpdir用作目录
  • 将本地目录用作目录(通常为/tmp)
char *tempnam(const char *dir, const char *pfx);
目 录 译者序 译者简介 前言 第1章 UNIX基础知识 1 1.1 引言 1 1.2 登录 1 1.2.1 登录名 1 1.2.2 shell 1 1.3 文件和目录 2 1.3.1 文件系统 2 1.3.2 文件名 2 1.3.3 路径名 2 1.3.4 工作目录 4 1.3.5 起始目录 4 1.4 输入和输出 5 1.4.1 文件描述符 5 1.4.2 标准输入、标准输出和标准 出错 5 1.4.3 不用缓存的I/O 5 1.4.4 标准I/O 6 1.5 程序和进程 7 1.5.1 程序 7 1.5.2 进程和进程ID 7 1.5.3 进程控制 7 1.6 ANSI C 9 1.6.1 函数原型 9 1.6.2 类属指针 9 1.6.3 原始系统数据类型 10 1.7 出错处理 10 1.8 用户标识 11 1.8.1 用户ID 11 1.8.2 组ID 12 1.8.3 添加组ID 12 1.9 信号 12 1.10 UNIX时间值 14 1.11 系统调用和函数 14 1.12 小结 16 习题 16 第2章 UNIX标准化及实现 17 2.1 引言 17 2.2 UNIX标准化 17 2.2.1 ANSI C 17 2.2.2 IEEE POSIX 18 2.2.3 X/Open XPG3 19 2.2.4 FIPS 19 2.3 UNIX实现 19 2.3.1 SVR4 20 2.3.2 4.3+BSD 20 2.4 标准和实现的关系 21 2.5 限制 21 2.5.1 ANSI C限制 22 2.5.2 POSIX限制 22 2.5.3 XPG3限制 24 2.5.4 sysconf、pathconf 和fpathconf 函数 24 2.5.5 FIPS 151-1要求 28 2.5.6 限制总结 28 2.5.7 未确定的运行时间限制 29 2.6 功能测试宏 32 2.7 基本系统数据类型 32 2.8 标准之间的冲突 33 2.9 小结 34 习题 34 第3章 文件I/O 35 3.1 引言 35 3.2 文件描述符 35 3.3 open函数 35 3.4 creat函数 37 3.5 close函数 37 3.6 lseek函数 38 3.7 read函数 40 3.8 write函数 41 3.9 I/O的效率 41 3.10 文件共享 42 3.11 原子操作 45 3.11.1 添加至一个文件 45 3.11.2 创建一个文件 45 3.12 dup和dup2函数 46 3.13 fcntl函数 47 3.14 ioctl函数 50 3.15 /dev/fd 51 3.16 小结 52 习题 52 第4章 文件和目录 54 4.1 引言 54 4.2 stat, fstat和lstat函数 54 4.3 文件类型 55 4.4 设置-用户-ID和设置-组-ID 57 4.5 文件存取许可权 58 4.6 新文件和目录的所有权 60 4.7 access函数 60 4.8 umask函数 62 4.9 chmod和fchmod函数 63 4.10 粘住位 65 4.11 chown, fchown和 lchown函数 66 4.12 文件长度 67 4.13 文件截短 68 4.14 文件系统 69 4.15 link, unlink, remove和rename 函数 71 4.16 符号连接 73 4.17 symlink 和readlink函数 76 4.18 文件的时间 76 4.19 utime函数 78 4.20 mkdir和rmdir函数 79 4.21 读目录 80 4.22 chdir, fchdir和getcwd函数 84 4.23 特殊设备文件 86 4.24 sync和fsync函数 87 4.25 文件存取许可权位小结 88 4.26 小结 89 习题 89 第5章 标准I/O 91 5.1 引言 91 5.2 流和FILE对象 91 5.3 标准输入、标准输出和标准出错 91 5.4 缓存 91 5.5 打开流 94 5.6 读和写流 96 5.6.1 输入函数 96 5.6.2 输出函数 97 5.7 每次一行I/O 98 5.8 标准I/O的效率 99 5.9 二进制I/O 100 5.10 定位流 102 5.11 格式化I/O 103 5.11.1 格式化输出 103 5.11.2 格式化输入 103 5.12 实现细节 104 5.13 临时文件 105 5.14 标准I/O的替代软件 108 5.15 小结 108 习题 108 第6章 系统数据文件和信息 110 6.1 引言 110 6.2 口令文件 110 6.3 阴影口令 112 6.4 组文件 113 6.5 添加组ID 114 6.6 其他数据文件 115 6.7 登录会计 116 6.8 系统标识 116 6.9 时间和日期例程 117 6.10 小结 121 习题 121 第7章 UNIX进程的环境 122 7.1 引言 122 7.2 main 函数 122 7.3 进程终止 122 7.3.1 exit和_exit函数 122 7.3.2 atexit函数 124 7.4 命令行参数 125 7.5 环境表 126 7.6 C程序的存储空间布局 126 7.7 共享 127 7.8 存储器分配 128 7.9 环境变量 130 7.10 setjmp 和longjmp函数 132 7.10.1 自动、寄存器和易失变量 134 7.10.2 自动变量的潜在问题 136 7.11 getrlimit 和setrlimit函数 136 7.12 小结 139 习题 140 第8章 进程控制 141 8.1 引言 141 8.2 进程标识 141 8.3 fork函数 142 8.4 vfork 函数 145 8.5 exit函数 147 8.6 wait和waitpid函数 148 8.7 wait3和wait4函数 152 8.8 竞态条件 153 8.9 exec函数 156 8.10 更改用户ID和组ID 160 8.10.1 setreuid 和setregid函数 162 8.10.2 seteuid和 setegid函数 163 8.10.3 组ID 163 8.11 解释器文件 164 8.12 system函数 167 8.13 进程会计 171 8.14 用户标识 175 8.15 进程时间 176 8.16 小结 178 习题 178 第9章 进程关系 180 9.1 引言 180 9.2 终端登录 180 9.2.1 4.3+BSD终端登录 180 9.2.2 SVR4终端登录 182 9.3 网络登录 182 9.3.1 4.3+BSD网络登录 182 9.3.2 SVR4网络登录 183 9.4 进程组 183 9.5 对话期 184 9.6 控制终端 185 9.7 tcgetpgrp 和tcsetpgrp函数 187 9.8 作业控制 187 9.9 shell执行程序 189 9.10 孤儿进程组 193 9.11 4.3+BSD实现 195 9.12 小结 197 习题 197 第10章 信号 198 10.1 引言 198 10.2 信号的概念 198 10.3 signal函数 203 10.3.1 程序起动 205 10.3.2 进程创建 206 10.4 不可靠的信号 206 10.5 中断的系统调用 207 10.6 可再入函数 209 10.7 SIGCLD语义 211 10.8 可靠信号术语和语义 213 10.9 kill和raise函数 213 10.10 alarm和pause函数 214 10.11 信号集 219 10.12 sigprocmask 函数 220 10.13 sigpending函数 222 10.14 sigaction函数 223 10.15 sigsetjmp 和siglongjmp函数 226 10.16 sigsuspend函数 229 10.17 abort函数 234 10.18 system函数 235 10.19 sleep函数 240 10.20 作业控制信号 241 10.21 其他特征 243 10.21.1 信号名字 243 10.21.2 SVR4信号处理程序的附 加参数 244 10.21.3 4.3+BSD信号处理程序的附 加参数 244 10.22 小结 244 习题 244 第11章 终端I/O 246 11.1 引言 246 11.2 综述 246 11.3 特殊输入字符 250 11.4 获得和设置终端属性 254 11.5 终端选择标志 254 11.6 stty命令 258 11.7 波特率函数 259 11.8 行控制函数 260 11.9 终端标识 260 11.10 规范方式 263 11.11 非规范方式 266 11.12 终端的窗口大小 270 11.13 termcap, terminfo和 curses 271 11.14 小结 272 习题 272 第12章 高级I/O 273 12.1 引言 273 12.2 非阻塞I/O 273 12.3 记录锁 275 12.3.1 历史 276 12.3.2 fcntl记录锁 276 12.3.3 锁的隐含继承和释放 280 12.3.4 4.3+BSD的实现 281 12.3.5 建议性锁和强制性锁 284 12.4 流 288 12.4.1 流消息 289 12.4.2 putmsg和putpmsg函数 290 12.4.3 流ioctl操作 291 12.4.4 write至流设备 294 12.4.5 写方式 294 12.4.6 getmsg和getpmsg函数 294 12.4.7 读方式 295 12.5 I/O多路转接 296 12.5.1 select函数 298 12.5.2 poll函数 301 12.6 异步I/O 303 12.6.1 SVR4 303 12.6.2 4.3+BSD 303 12.7 readv和writev函数 304 12.8 readn和writen函数 306 12.9 存储映射I/O 307 12.10 小结 311 习题 311 第13章 精灵进程 312 13.1 引言 312 13.2 精灵进程的特征 312 13.3 编程规则 313 13.4 出错记录 314 13.4.1 SVR4流log驱动程序 315 13.4.2 4.3+BSD syslog设施 316 13.5 客户机-服务器模型 319 13.6 小结 319 习题 319 第14章 进程间通信 320 14.1 引言 320 14.2 管道 320 14.3 popen和pclose函数 325 14.4 协同进程 330 14.5 FIFO 333 14.6 系统V IPC 335 14.6.1 标识符和关键字 336 14.6.2 许可权结构 337 14.6.3 结构限制 337 14.6.4 优点和缺点 337 14.7 消息队列 338 14.8 信号量 342 14.9 共享存储 346 14.10 客户机-服务器属性 351 14.11 小结 353 习题 353 第15章 高级进程间通信 355 15.1 引言 355 15.2 流管道 355 15.3 传送文件描述符 358 15.3.1 SVR4 360 15.3.2 4.3BSD 361 15.3.3 4.3+BSD 364 15.4 open服务器第1版 366 15.5 客户机-服务器连接函数 371 15.5.1 SVR4 372 15.5.2 4.3+BSD 375 15.6 open服务器第2版 378 15.7 小结 385 习题 385 第16章 数据函数 386 16.1 引言 386 16.2 历史 386 16.3 函数 386 16.4 实现概述 388 16.5 集中式或非集中式 390 16.6 并发 391 16.6.1 粗锁 391 16.6.2 细锁 391 16.7 源码 392 16.8 性能 409 16.8.1 单进程的结果 410 16.8.2 多进程的结果 410 16.9 小结 412 习题 412 第17章 与PostScript打印机通信 413 17.1 引言 413 17.2 PostScript通信机制 413 17.3 假脱机打印 415 17.4 源码 417 17.5 小结 434 习题 434 第18章 调制解调器拨号器 435 18.1 引言 435 18.2 历史 435 18.3 程序设计 436 18.4 数据文件 437 18.5 服务器设计 439 18.6 服务器源码 439 18.7 客户机设计 463 18.7.1 终端行规程 463 18.7.2 一个进程还是两个进程 464 18.8 客户机源码 465 18.9 小结 474 习题 474 第19章 伪终端 476 19.1 引言 476 19.2 概述 476 19.2.1 网络登录服务器 477 19.2.2 script程序 478 19.2.3 expect程序 479 19.2.4 运行协同进程 479 19.2.5 观看长时间运行程序的输出 479 19.3 打开伪终端设备 480 19.3.1 SVR4 481 19.3.2 4.3+BSD 482 19.4 pty_fork函数 484 19.5 pty程序 486 19.6 使用pty程序 489 19.6.1 utmp文件 489 19.6.2 作业控制交互 489 19.6.3 检查长时间运行程序的输出 491 19.6.4 script程序 491 19.6.5 运行协同进程 492 19.6.6 用非交互模式驱动交互式 程序 492 19.7 其他特性 494 19.7.1 打包模式 494 19.7.2 远程模式 494 19.7.3 窗口大小变化 495 19.7.4 信号发生 495 19.8 小结 495 习题 495 附录A 函数原型 497 附录B 其他源代码 512 附录C 习题答案 518 参考书目 536
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值