《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的程序
gcc test.c -o test这样将编译出一个名为test的程序,-o参数用来指定生成程序的名字
编译:
第一步、是进行预编译,使用-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. 消息队列
十二:网路编程 十三:底层终端编程