unix环境高级编程学习

Unix环境高级编程  apue.h文件配置

apue.h下载

tar -zxvf src.3e.tar.gz

cd apue.3e/

sudo apt-get install libbsd-dev 

make

sudo cp ./include/apue.h /usr/include/

sudo cp ./lib/libapue.a /usr/local/lib/

gcc ls.c -o ls -lapue 或者cc ls.c -lapue (需要链接静态库)默认生成a.out文件 ./a.out + 路径

./ls /home

ls命令

ls > file.list 将文件标准输出重定向到名为file.list文件中。

open,read,write,lseek,close提供了不带缓冲的I/O,这些函数使用文件描述符。

内核:内核从本质上看是一种软件——控制计算机的硬件资源,并提供上层应用程序运行的环境

用户态:只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。

内核态:cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。

用户态和内核态的切换:

1)系统调用

2)异常事件: 当CPU正在执行运行在用户态的程序时,突然发生某些预先不可知的异常事件,这个时候就会触发从当前用户态执行的进程转向内核态执行相关的异常事件,典型的如缺页异常。

3)外围设备的中断:当外围设备完成用户的请求操作后,会像CPU发出中断信号,此时,CPU就会暂停执行下一条即将要执行的指令,转而去执行中断信号对应的处理程序,如果先前执行的指令是在用户态下,则自然就发生从用户态到内核态的转换。


系统调用:用户进程进入内核的接口层,它本身并非内核函数,但他是由内核函数实现的,进入系统内核后,不同的系统调用会找到各自对应的内核函数,这些内核函数被称为系统调用的“服务例程”。也可以说系统调用是服务例程的封装例程,系统调用是操作系统的最小功能单位。书上定义:所有操作系统都提供多种服务的入口点,由此程序向内核请求服务。各种版本的unix实现都提供良好定义,数量有限,直接进入内核的入口点,这些入口点被称为系统调用(system call)。

系统调用和库函数的区别:从用户角度来看,其区别并不重要。两者都以c函数的形式出现,两者都为应用程序提供服务。两者职责不同,内核系统调用分配一块空间给进程,而库函数malloc则在用户层次管理这一空间。应用程序既可以调用系统调用也可以调用库函数。系统调用通常提供最小接口,而库函数通常提供比较复杂的功能。

文件类型

(1)普通文件(regular file).这是最常用的文件类型,这种文件包含了某种形式的数据。至于这种数据是文本还是二进制数据,对于UNIX内核而言并无区别。对于普通文件内容的解释由处理文件的应用程序进行。 
(一个值得注意的例外是二进制可执行文件。为了执行程序,内核必须理解其格式。所有二进制可执行文件都遵循一种标准化的格式,这种格式使内核能够确定程序文本和数据加载的位置,比如windows上面的EXE可执行文件放到UNIX下就不能执行,因为UNIX不知道EXE程序文本和数据加载的位置。)

(2)目录文件(directory file)。这种文件包含了其他文件的命字以及指向与这些文件有关信息的指针。对一个目录文件具有读权限的任一进程都可以读该目录的内容,但只有内核可以直接写目录文件。进程必须使用函数才能更改目录。

(3)块特殊文件(block special file)。这种类型的文件提供对设备(如磁盘)带缓冲的访问,每次访问可以固定长度为单位进行。 
**注意:**FreeBSD不再支持块特殊文件。对设备的所有访问需要通过字符串特殊文件进行。

(4)字符特殊文件(character special file)。这种类型的文件提供对设备不带缓冲的访问,每次访问长度可变。系统中所有设备要么是字符特殊文件,要么是块特殊文件。

(5)FIFO。这种类型的文件用于进程间通信,有时也称为命名管道(named pipe)

(6)套接字(socket)。这种类型的文件用于进程间的网络通信。套接字也可用于在一台宿主机上进程之间的非网络通信。

(7)符合链接(symbolic link).这种类型的文件指向另一个文件。

>, >> 重定向

>:将一条命令执行结果(标准输出,或者错误输出,本来都要打印到屏幕上面的)重定向其它输出设备(文件,打开文件操作符,或打印机等等)

< :命令默认从键盘获得的输入,改成从文件,或者其它打开文件以及设备输入

>> 是追加内容

> 是覆盖原有内容


int argc, char **argv 用于运行时,把命令行参数传入主程序。
argc -- 命令行参数 总个数,包括 可执行程序名。
argv[i] -- 第 i 个参数。
argv[0] -- 可执行程序名。

#include <apue.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
    DIR *dp;
    struct dirent *dirp;
    if(argc!=2)
     err_quit("usage: ls directory_name");
   if((dp=opendir(argv[1]))==NULL)
     err_sys("can't open %s", argv[1]);
while((dirp = readdir(dp))!=NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
exit(0);
}
#include <apue.h>
#define BUFFSIZE 4096
int main(void)
{
    int n;
char buf[BUFFSIZE];
while((n==read(STDIN_FILENO,buf,BUFFSIZE))>0)//read返回读取的字节数
if(write(STDOUT_FILENO, buf, n)!=n)
err_sys("write error");
if(n<0)
err_sys("read error");
exit(0);
}
#include "apue.h"
#include <sys/wait.h>
int main(void)
{
	char buf[MAXLINE];
	pid_t pid;
	int status;
	printf("%% ");//字符转义
	while(fgets(buf, MAXLINE,stdin)!=NULL)//重流中读入文件
	{
		if(buf[strlen(buf)-1]=='\n')
			buf[strlen(buf)-1]=0;
		if((pid = fork())<0)
		{err_sys("fork error");}
		else if(pid ==0)
		{
			execlp(buf, buf,(char *)0);
			err_ret("couldn't execute: %s", buf);
			exit(127);
		}

		if((pid=waitpid(pid,&status,0))<0)
			err_sys("waitpid error");
		printf("%% ");	
	}
	exit(0);	
}



猜你喜欢

转载自blog.csdn.net/fanhansheng/article/details/79939214