《Linux环境下C编程指南》知识总结 一:C语言基础 1. 数据类型 2. 运算符表达式 3. C程序语句 4. 函数 5. 编译预处理
二:vi与emacs 2.1 vi启动退出 2.2 命令行操作 $ 将光标移动到该行最后 G 移动到最后一行开头 nG 将光标移动到n行行首 Z+Z 表示保存并退出vim % 符号匹配功能 “%a”将匹配到 相应的“a” . 重复执行上一命令 u 表示复原功能 y+y 将光标目前所在位置整行复制 n+y+y 若按下3yy 则将光标所在行与下面两行一起复制 p 将复制的内容整行粘贴在光标所在位置 d+左方向键 将光标前一个字符删除 d+右 将光标当前字符删除 d+上 上一行全部删除 d+ 下 下一行全部删除 d+d 删除当前行 n+d+d 向下删除n行 n+d+下 向下删除n行 n+d+上 向上删除n行 2.3 命令行模式与输入模式切换 2.4 最后行操作 :set nu 设置行号 :/ 查找字符串,“/字符串”将高亮显示字符串,n向下找一个,N向上找一个,由上向下。 :? “?字符串”由下向上查找字符串,
三:gcc Gcc 选项,警告,优化,调试标记,高级选项 从功能上分,预处理、编译、汇编是三个不同的阶段,但GCC的实际操作上,它可以把这三个步骤合并为一个步骤来执行。 gcc test.c这样将编译出一个名为a.out的程序
编译: 第一步、是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程: gcc -E hello.c -o hello.i 预处理的宏定义插入到hello.i中 第二步、是将hello.i编译为目标代码,这可以通过使用-c参数来完成: gcc -c hello.i -o hello.o 也可以通过源文件直接生成 gcc -c hello.c 第三步、是将生成的目标文件链接成可执行文件: gcc hello.o -o hello 也可以通过源文件直接生成 gcc -o hello hello.c ,因为警告: 1、-pedantic 选项,那么使用了扩展语法的地方将产生相应的警告信息 2、-Wall 使用它能够使GCC产生尽可能多的警告信息 3、-Werror,它要求GCC将所有的警告当成错误进行处理 库依赖: 1、Linux下的大多数函数都默认: 头文件放到/usr/include/目录下 而库文件则放到/usr/lib/目录下 2、GCC在编译时必须有自己的办法来查找所需要的头文件和库文件。 -I选项可以向GCC的头文件搜索路径中添加新的目录。 例如,如果在/home/xiaowp/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项: gcc -o test test.c -I /home/xiaowp/include -L选项向GCC的库文件搜索路径中添加新的目录 例如,如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so,为了让GCC能够顺利地找到它,可以使用下面的命令 gcc -o test test.c -L /home/xiaowp/lib -lfoo 值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。 Linux下的库文件在命名时有一个约定,那就是应该以lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo进行处理时,会自动去链接名为libfoo.so的文件。 -static选项,强制使用静态链接库 如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so和libfoo.a 为了让GCC在链接时只用到静态链接库,可以使用下面的命令: gcc -o test test.c -L /home/xiaowp/lib -static -lfoo 选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。 在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。 选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。 选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。 通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。 许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。 time ./test 查看程序执行时间 优化虽然能够给程序带来更好的执行性能,但在如下一些场合中应该避免优化代码: 程序开发的时候优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。 资源受限的时候一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。 跟踪调试的时候在对代码进行优化的时候,某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。 加速: 使用管道代替编译中临时文件, -pipe 加速编译 gcc -pipe foo.c -o foo GCC常用选项 -c 通知GCC取消链接步骤,即编译源码并在最后生成目标文件; -Dmacro 定义指定的宏,使它能够通过源码中的#ifdef进行检验; -E 不经过编译预处理程序的输出而输送至标准输出; -g3 获得有关调试程序的详细信息,它不能与-o选项联合使用; -Idirectory 在包含文件搜索路径的起点处添加指定目录; -llibrary 提示链接程序在创建最终可执行文件时包含指定的库; -O、-O2、-O3 将优化状态打开,该选项不能与-g选项联合使用; -S 要求编译程序生成来自源代码的汇编程序输出; -v 启动所有警报; -Wall 在发生警报时取消编译操作,即将警报看作是错误; -Werror 在发生警报时取消编译操作,即把报警当作是错误; -w 禁止所有的报警。 基本上用不到;若非要生成这种文件 不可,可以利用下面的示例命令:行功能上分,预处理、编译、汇编是三个不同的阶段,但GCC的实际操作上,它可以把这三个步骤合并为一个步骤来执行 四:dgb 调试步骤,显示数据,使用断点,使用观察窗口,查看栈信息,查看源信息,查看运行时数据,改变程序执行,core dump 分析
五:使用make 1. make 书写规范 2. 使用命令 3. 使用变量 4. 使用条件判断 5. 使用函数 6. make运行 7. 隐含规则 8. make给新函数库文件 9. 高级使用 10. 库使用
六:进程控制 1. 进程基本概念 2. 进程相关函数 3. 多个进程间的关系 4. 线程
pid_t getpid(void); pid_t getppid(void); pid_t getuid(void); pid_t geteuid(void); pid_t getgid(void); pid_t getegid(void); 上面这些函数分别用于获得当前进程的:进程ID、父进程ID、实际用户ID、有效用户ID、实际组ID和有效组ID。 相关函数 pid_t fork(void); pid_t vfork(void); 说明 除了init等系统进程以外,创建进程的唯一方法就是调用fork函数。调用fork后,子进程完全复制父进程。对子进程,fork返回0;对父进程,fork返回子进程的pid。vfork并不复制父进程的进程空间,在子进程调用exec或者exit之前,子进程在父进程的进程空间运行。 文件共享 子进程继承了父进程打开的文件描述符及其文件位移量,所以可能产生冲突,需要进行同步,也可以父进程等待子进程完成或者父、子进程执行不同的程序段以避免冲突。 fork的用法 父进程希望复制自己,使父、子进程执行不同的代码段。 一个进程要调用一个不同的程序。 相关函数 pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status,int options); 说明 status返回所等待进程的返回状态,可以用一系列的宏来检查这个状态。 调用这两个函数后,当前进程可能会: 阻塞(如果其所以子进程都还在运行) 带子进程的终止状态立刻返回(如果一个子进程以终止,正在等待父进程存取其终止状态) 出错立刻返回(如果它没有任何子进程) 区别 在一个子进程终止前,wait是其调用者阻塞,而waitpid有一选择项可以是调用者不阻塞。 waitpid并不等待第一个终止的子进程,它有选择项可以控制它所等待的进程。 相关函数 int execve(const char *path, char *const argv [], char *const envp[]); int execl(const char *path,const char *arg, ...); int execlp(const char *file,const char *arg, ...); int execle(const char *path, const char *arg , ..., char * const envp[]); int execv(const char *path,char *const argv[]); int execvp(const char *file,char *const argv[]); 区别 以上6个函数中execve时系统调用,其他的则是库函数。 根据函数名中的字符: p表示该函数取文件名作为参数,并用PATH环境变量寻找可执行文件。没有字符p则表示参数为完全路径名。 l表示该函数取一个参数表,它和字符v互斥。v表示该函数取一个参数的数组argv[]。 e表示该函数取envp[]数组作为新程序的环境变量表,没有e则使用当前进程的环境变量表。 设置用户ID和组ID 相关函数 int setuid(uid_t uid); int setgid(uid_t gid); <!--[if !supportEmptyParas]--> <!--[endif]--> int seteuid(uid_t euid); int setegid(gid_t egid); <!--[if !supportEmptyParas]--> <!--[endif]--> int setreuid(uid_t ruid, uid_teuid); int setregid(gid_t rgid, gid_tegid); 规则 关于用setuid函数改变用户ID的规则(也同样适用于setgid函数): 若进程具有root特权,则setuid把RUID、EUID以及SUID都设置为uid。 若进程没有root权限,但uid等于RUID或者SUID,则把EUID设置为uid。 上述条件都不满足,则返回出错,errno设为EPERM。 执行shell程序 相关函数 int system(const char *cmd); 说明 相当于执行/bin/sh –c cmd. 对于有suid和sgid权限的程序不能使用此函数,会产生安全漏洞。 相关函数 char *getlogin(void); 说明 得到运行该程序的用户的登录名。对于未连接到终端的进程,本函数会失败。 相关函数 clock_t times(struct tms *buf); 说明 用于得到进程自己以及终止子进程的用户CPU时间和系统CPU时间。
七:文件操作 1.文件系统简介 2.基于文件描述符的I/O 操作 3.文件其他操作 4.特殊文件操作 八:基于流的输入输出 1. 流简介 2. 基于流的I/O 操作 3. 临时文件
linux系统调用与文件I/O操作 linux系统调用 所谓系统调用是指操作系统提供给用户程序的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得得操作系统内核提供的特殊服务。 在linux中用户程序不能直接访部内核提供的服务。为了更好的保护内核空间,将程序的运行空间分为内核空间和用户空间,他们运行在不同的级上,在逻辑上是相互隔离的。 用户程序接口(API) 在linux中用户编程接口(API)遵循了在UNIX中最流行的应用编程界面标准——POSIX标准。这些系统调用编程接口主要通过C库(libc)实现的。 系统调用、API与系统命令之间的关系见图 文件I/O操作介绍 可用的文件I/O函数——打开文件、读文件、写文件等等。大多数linux文件I/O只需用到5个函数:open、read、write、lseek以及close。不带缓存指的是每read和write都调用内核中的一个系统调用。这些不带缓存的I/O函数不是ANSIC的组成部分,但是POSIX组成部分。 文件描述符 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用open或creat返回的文件描述符标识该文件,将其作为参数传送给read或write。在POSIX.1应用程序中,整数0、1、2应被代换成符号常数STDIN_FILEN0、STDOUT_FILENO和STDERR_FILENO。这些常数都定义在头文件<unistd.h>中 文件描述符的范围是0~OPEN_MAX。早期的UNIX版本采用的上限值是19(允许每个进程打开20个文件),现在很多系统则将其增加至63。 open函数 #include<sys/types.h> #include<sys/stat.h> #inlcude<fcntl.h> int open(const char *pathname,int oflag,.../*,mode_t mode*/); 返回:若成功为文件描述符,若出错为-1 pathname是要打开或创建的文件的名字。 oflag参数可用来说明此函数的多个选择项。 对于open函数而言,仅当创建新文件时才使用第三个参数。 用下列一个或多个常数进行或运算构成oflag参数(这些常数定义在
<fcntl.h>头文件中): O_RDONLY只读打开。 O_WRONLY只写打开。 O_RDWR读、写打开。 O_APPEND每次写时都加到文件的尾端。 O_CREAT若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位。 O_EXCL如果同时指定了O_CREAT,而文件已经存在,则出错,这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作。 O_TRUNC如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。 O_NOCTTY如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端。 O_NONBLOCK如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。 O_SYNC使每次write都等到物理I/O操作完成。
creat函数 可用creat函数创建一个新文件。 #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> int creat(const char *pathname,mode_t mode); 返回:若成功只为写打开的文件描述符,若出错为-1。注意,此函数等效于: open (pathname,O_WRONLY |O_CREAT| O_TRUNC,mode); creat的一个不足之处是它以只写方式打开所创建的文件。
close函数 可用close函数关闭一个打开文件: #include<unistd.h> int close(int filedes); 返回:若成功为0,若出错为-1 当一个进程终止时,它所有的打开文件都由内核自动关闭。很多程序都使用这一功能而不显式地用close关闭打开的文件。 如open.c #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #inlcude<stdlib.h> #include<stdio.h>
int main(void){ int fd; if(fd=open("/tmp/hello.c",O_CREAT|O_TRUNC|O_WRONLY,0600))<0){ perror("open:"); exit(1); }else printf("open fiale:hello.c%d/n",fd);
if(close(fd)<0){ perror("close:"); exit(1); } else printf("Close hello.c/n"); exit(0); }
lessk函数——文件定位 每个打开文件都有一个与其相关联的“当前文件偏移量”。它是一个非负整数,用以度量从文件开始处计算的字节数。通常,读、写操作都从当前文件偏移理处开始,并使偏移理增加所计或写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该偏移量被设置为0。可以调用lseek显式地定位一个打开文件。 #include<sys/types.h> #include<unistd.h> off_t lseek(it filesdes,off_t offset,int whence); 返回:若成功为新文件位移,若出错为-1。 对于参数offset的解释与参数whence的值有关。 若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处offset个字节。若whence是SEEK_CUR,则将该文件的位移量设置为其当前值加offset,offset可为正或负。若whence是SEEK_END,则将该文件的位移量设置为文件长度加offset,offset可为正或负。若lseek成功执行,则返回新的文件位移量,为此可以用下列方式确定一个打开文件的当前位移量: off_t currpos; currpos=lseek(fd,0,SEEK_CUR);
read函数 用read函数从打开文件中读数据 #include<unistd.h> ssize_t read(int feledes,void *buff,size_t nbytes); 返回:读到的字节数,若已到文件尾为0,若出错为-1。如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。有多种情况可使实际读到的字节数小于要求读字节数: 读普通文件时,在读到要求字节数之前已到达了文件尾端。例如,若在到达文件尾端之间还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将返回0(文件尾端)。当从终端设备读时,通常一次最多读一行。 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。某些面向记录的设备,例如磁带,一次最多返回一个记录。读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数。
write函数 用write函数向打开文件写数据。 #include<unistd.h> ssize_t write(int filedes,const void *buff,size_t nbytes); 返回:若成功为已写的字节数,若出错为-1。其返回值通常与参数
nbytes的值不同,否则表示出错。write出错的一个常见原因是:磁盘已写满,或者超过了对一个给定进程的文件长度限制。 对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。见write.c #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #define MAXSIZE int main(void){ int i,fd,size,len; char *buf="Hello! I'm writing to this file!"; char buf_r[10]; len=strlen(buf); buf_r[10]='/0'; if((fd=open("/tmp/hello.c",O_CREAT | O_TRUNC | O_RDWR,0666)
<0){ perror("open:"); exit(1); }else printf("open file hello.c %d/n",fd);
if((size=write(fd,buf,len))<0){ perror("write:"); exit(1); }else printf("Write %s/n",buf);
lseek(fd,0,SEEK_SET); if((size=read(fd,buf_r,10))<0){ perror("read:"); exit(1); }else printf("read form file:%s/n",buf_r);
if(close(fd)<0){ perror("close:"); exit(1); }else printf("Close hello.c/n");exit(0); }
fcntl函数 fcntl函数可以改变已经打开文件的性质。 #include<sys/types.h> #inlcude<unistd.h> #inlcude<fcntl.h> int fcntl(int filedes,int cmd,....); 返回:若成功则依赖于cmd,若出错为-1。 fcntl函数有五种功能: (1)复制一个现存的描述符,新文件描述符作为函数值返回
(cmd=F_DUPFD). (2)获得/设置文件描述符标记,对应于filedes的文件描述符标志作为函数值返回。(cmd=F_GETFD或F_SETFD)。 (3)获得/设置文件状态标志,对应于filedes的文件状态标志作为函数值返回。(cmd=F_GETEL或F_SETFL)。 (4)获得/设置异步I/O有权(cmd=F_GETOWN或F_SETOWN)。 (5)获得/设置记录锁(cmd=F_SETLK,F_SETLKW)。 文件状态的说明见附件。
F_SETFL将文件状态设置为第三个参数的值(取为整型值)。可以更改的几个标志是:O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC. F_GETOWN取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。 F_SETOWN设置接收SIGIO和SIGURG信号的进程ID或进程组ID。正的arg指定一个进程组ID,负的arg表示等于arg绝对值的一个进程组ID。
用fcntl给文件加锁 当多个用户共同使用、操作一个文件的时候,linux通常采用的方未能是给文件上锁,来避免共享资源产生竞争的状态。 文件锁包括建议锁和强制性锁。建议性锁要求上锁文件的进程都要检测是否有锁存在,并尊重已有的锁。强制性锁由内核和系统执行的锁。Fcntl不仅可以实施建议性锁而且还可以实施强制性锁。
fcntl函数格式 #include<sys/types.h> #include<unistd.h> #include<fcntl.h> int fcntl(int filedes,int cmd,... struct flock flockptr); struct flock 结构 struct flock{ short l_type; /*F_RDLCK,F_WRLCK, F_UNCLK */ off_t l_start; /*offset in bytes,relative to l_whence */ short l_whence; /*SEEK_SET,SEEK_CUR,SEEK_END */ off_t len; /*length,in bytes */ pid_t l_pid; /* returned with F_GETLK */ };
flock结构说明:所希望的锁类型:F_FDLCK(共享读锁)、F_WRLCK(独占性写锁)或F_UNLCK(解锁一个区域)。要加锁或解锁的区域的起始地址,由l_start和l_whence两者决定。l_start是相对位移量(字节),l_whence则决定了相对位移量的起点。区域的长度,早l_len表示。 关于加锁和解锁区域的说明还要注意下列几点: (1)该区域可以在当前文件尾端处开始或越过其尾端处开始,但是不能在文件起始位置之前开始或越过该起始位置。 (2)如若l_len为0 ,则表示锁的区域从其起点(由l_start和
l_whence决定)开始直至最大可能位置为止。也就是不管添写到该文件中多少数据,它都处于锁的范围。 (3)为了锁整个文件,通常的方法是将l_start说明为0,l_whence说明为SEEK_SET,l_len说明为0。
ioctl函数 还得查其它资料 ioctl函数是I/O操作的杂物箱。不能用本章中其他函数表示的I/O操作通常都能用ioctl表示。终端I/O是ioctl的最大使用方面,主要用于设备的I/O控制。 #include<unistd.h> /*SVR4*/ #include<sys/ioctl.h> /*4.3 +BSD * / int ioctl(int filedes,int request,....); 返回:若出错则为-1,若成功则为其他值。
selelct实现I/O复用 I/O处理的五种模型 (1)阻塞I/O模型:若所调用的I/O函数没有完成相关的功能就会使进程挂起,直到相关数据到达才会返回。如:终端、网络设备的访问。 (2)非阻塞模型:当请求的I/O操作不能完成时,则不让进程休眠,而且返回一个错误。如:open,read,write访问。 (3)I/O多路转接型:如果请求的I/O操作阻塞,且他不是真正阴塞I/O,而且让其中的一个函数等待,在这期间,I/O还能进行其他操作。如:select函数。 (4)信号驱动I/O模型:在这种模型下,通过安装一个信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。 (5)异步I/O模型:在这种模型下,当一个描述符已准备好,可以启动I/O时,进程会通知内核。由内核进行后续处理,这种用法现在较少。 关心第一种、第三种和第四种模型,用的比较多。 传向select的参数告诉内核: (1)我们所关心的描述符。 (2)对于每个描述符我们所关心的条件(是否读一个给定的描述符?是否想烈军属一个给定的描述符?是否关心一个描述符的异常条件?)。 (3)希望等待多长时间(可以永远等待,等待一个固定量时间,或完全不等待)。 从select返回时,内核告诉我们: (1)已准备好的描述符的数量。 (2)哪一个描述符已准备好读、写或异常条件。 #include<sys/types.h>/*fd_set daya type*/ #include<sys/time.h>/*struct timeval*/ #inlcude<unistd.h>/*function prototype might be here*/ int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set
*execptfds,struct timeval *timeout); 返回:准备就绪的描述符数,若超时则为0,若出错则为-1。 timeout值: NULL:永远等待,直到捕捉到信号或文件描述符已准备好为止; 具体值:struct timeval类型的指针,若等待为timeout时间还没有文件描述符准备好,就立即返回; 0:从不等待,测试所有指定的描述符并立即返回; 先说明最后一个参数,它指定愿意等待的时间。 struct timeval{ long tv_sec; /*seconds*/ long tv_usec; /*and microseconds*/毫秒 }; select函数根据希望进行的文件操作对文件描述符进行分类处理,这里,对文件描述符的处理主要设计4个宏函数: FD_AERO(fd_set *set)清除一个文件描述符集; FD_SET(int fd, fd_set *set)将一个文件描述符加入文件描述符集中。 FD_CLR(int fd,fd_set *set)将一个文件描述符从文件描述符集中清除。 FD_ISSET(int fd,fd_set *set)测试该集中的一个给定位是否有变化; 在使用select函数之间,首先使用FD_ZERO和FD_SET来初始化文件描述符集,并使用select函数时,可循环使用FD_ISSET测试描述符集,在执行完成对相关的文件描述符后,使用FD_CLR来清除描述符集。例子见select.c #include<fcntl.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/time.h> int main(void){ int fds[2]; char buf[7]; int i,rc,maxfd; fd_set inset1,inset2; struct timeval tv; if((fds[0]=open("hello1",O_RDWR| O_CREAT,0666))<0) perror("open hello1"); if((fds[1]=open("hello2",O_RDWR|O_CREAT,0666))<0) perror("open hello2"); if((rc=write(fds[0],"Hello!/n",7)) printf("rc=%d/n",rc);
lseek(fds[0],0,SEEK_SET); maxfd=fds[0]>fds[1]?fds[0]:fds[1]; FD_ZERO(&inset1); FD_SET(fds[0],&inset1); FD_ZERO(&inset2); FD_SET(fds[1],&inset2);; tv.tv_sec=2; tv.tv_usec=0; while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2)){ if(select(maxfd+1,&inset1,&inset2,NULL,&tv)<0) perror("select"); else{ if(FD_ISSET(fds[0],&inset1)){ rc=read(fds[0],buf,7); if(rc>0){ buf[rc]='/0'; printf("read:%s/n",buf); }else perror("read"); } if(FD_ISSET(fds[1],&inset2)){ rc=write(fds[1],buf,7); if(rc>0){ buf[rc]='/0'; printf("rc=%d,write:%s/n",rc,buf); }else perror("write"); sleep(10); } } } exit(0); } 读取hello1文件的内容,写入到hello2文件中去。
系统I/O 来自CSDN博客:http://blog.csdn.net/xp55699312/archive/农历二〇〇九年三月初十/4050285.aspx
九:内存管理 1. 静态内存与动态内存 2. 安全性问题 3. 内存管理操作 4. 使用链表 5. 内存映射I/O
十:信号及信号处理 1. 信号及其使用简介 2. 信号操作的相关系统调用 3. 信号处理潜在危险
十一:进程间通信 1. 简介 一般包括:内存共享,信号量,管道,命名管道,消息队列,套接口,全双工管道 2. 共享内存和信号量 什么是sysv? Shmid_da 结构如何定义? 共享内存的创建与打开 int shmget (key_t,int size,int flag); 附加函数 Void *shmat (int shmid,void *addr,int flag); 分离 Int shmdt (void *addr); 控制共享内存 Int shmctl (int shmid,int cmd,shmid_ds *buf); 信号量数据结构 Semid_ds 信号量的创建与打开 Int semget (key_t key,int nsems,int flag); 操作 Int semop (int semid,sttruct sembuf semoparray[],size_t nops); 控制 Int semctl (int semid,int semnum,int cmd,union semun arg);-
3. 管道通信 管道的创建 Int pipe (int filedescriptos[2]); 4. 命名管道 5. 消息队列
十二:网路编程 十三:底层终端编程 |
|