linux 系统编程学习笔记一

文件与i/o


汇编程序的hello world
.data #section
declaration


msg:
.ascii "hello world!\n" #our dear
string
len= . - msg  #length of our
dear string


.text #section
declaration
  #we must export the entry


point to the ELF linker or
.global _start #loader.they conventionally
recognize _start as their
      #entry point. use ld -e foo to 
override the default.


_start:
#write our string to stdout
movl $len,%edx #third argument:
message length
movl $msg,%etc #second argument:
pointer to message to write
movl $1,%ebx #first argument: file
handle(stdout)
movl $4,%eax #system call number
(sys_write)
int $0x80 #call kernel
#and exit
movl $0,%ebx #first argument:exit
code
movl $1,%eax #system call number
(sys_exit)
int $0x80 #call  kernel


汇编:as -o hello.c hello.s
链接:ld -o hello hello.o
运行:./hello


以上代码等同于以下c代码:
#include <stdio.h>
char msg[14]="hello world!\n";
#define len 14


int main(void){
write(1,msg,len);
_exit(0);
}


c标准I/O与unbuffered I/O函数
c标准I/O用系统调用实现
fopen(3) 调用open打开文件,返回一个文件描述符,分配一个FILE结构体
fgetc(3) 通过传入的FILE参数,检查能否从I/O缓冲区读到下一个字符,如果
         能就直接读,否则就调用read(2),把文件描述符传进去,让内核读取该文件
到I/O缓冲区
fputc(3) 同上,如果i/o缓冲区已满就调用write(2),把缓冲区内容写入文件
fclose(3) 如果缓冲区有未写入,则调用write(2)写回文件,然后调用close(2)关闭文
          件,释放结构体和缓冲区


open\read\write\close等系统函数为无缓冲I/O(unbuffered I/O)


文件描述符:文件描述符表中的索引
每个进程linux内核都有一个task_struct结构体来维护进程相关信息,即进程描述符


(process descriptor) 或是进程控制块(pcb process control block)
task_struct中有一个指针指向files_struct结构体,称为文件描述符表


当调用open打开一个或创建一个新文件时,内核分配一个文件描述符返回给用户,
文件描述符表中的指针指向新打开文件


程序启动会打开三个文件:
   标准输入stdtin   文件描述符为0
   标准输出stdout               1
   标准错误输出stderr           2
 在头文件unistd.h中定义
  #define STDIN_FILENO 0
  #define STDOUT_FILENO 1
  #define STDERR_FILENO 2






open/close
open打开或创建一个文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*返回新分配的文件描述符,出错返回-1*/
/*
  pathname 文件名
  flag常数值
   必选项
   O_RDONLY 只读
   O_WRONLY 只写
   O_RDWR 可读可写
   可选项
    O_APPEND  追加
    O_CREAT   文件不存则创建 
    O_EXCL    
    O_TRUNC  如果文件已存在,且以只写或可读可写打开,则将其长度截断为0字节
 */
int open(const char *pathname,int flags);
/*mode指定文件权限,可用八进制表示,0644表示-rw-r--r--
 文件的权限由open的mode参数和当前进程的umask掩码决定
 */
int open(const char *pathname,int flags,mode_t mode);


close 关闭一个打开的文件
#include <stdio.h>
/*成功返回0
  fd为文件描述符
 */
int close(int fd);






read/write


read 从打开的文件或设备中读取数据
#include <unistd.h>
/*成功返回字节数,出错返回顾-1,如果在调用前已到达文件末尾,返回0*/
/*count 表示请求读取的字节数
  buf 数据保存缓冲区
  ssize_t 表示有符号的size_t 
 */
ssize_t read(int fd,void *buf,size_t count);


write 向打开的设备或文件中定数据
#include <unistd.h>
/*返回值通常等于count*/
ssize_t write(int fd,const void *buf,size_t count);


示例代码:
从终端读数据再写回终端
#include <unistd.h>
#include <stdlib.h>


/*阻塞读终端*/
int main(void){
char buf[10];
int n;
n=read(STDIN_FILENO,buf,10);
if(n<0){
perror("read stdin_fileno");
exit(1);
}
write(STDOUT_FILENO,buf,n);
return 0;
}








运行结果:
yuezhenhua@ubuntu:/opt/sdk/tc$ gcc test40.c -o test40
yuezhenhua@ubuntu:/opt/sdk/tc$ ./test40
hello
hello
yuezhenhua@ubuntu:/opt/sdk/tc$ ./test40
hello world
hello worlyuezhenhua@ubuntu:/opt/sdk/tc$ d
d:找不到命令


执行过程:
shell进程创建test40进程,test40开始执行,shell进程睡眠等待test40退出
test40调用read时睡眠等待,直到终端设备输入换行符才从read返回,read只读取10个字符
剩余的字符仍然保存在内核的终端设备输入缓冲区中
test40进程打印并退出,这时shell进程恢复运行,从终端设备读取用户输入的命令
于是读走了终端设备输入缓冲区中剩余的字符d和换行符,把它当作一条命令解释执行


监视多个设备
while(1){
非阻塞read(设备一);
if(设备一有数据到达){
处理数据;
}
非阻塞read(设备二);
if(设备二有数据到达){
处理数据;
}
/*延迟一会儿再查询*/
sleep(n);
}
注:select(2)函数可以在阻塞的同时监视多个设备






#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
 
#define MSG_TRY "try again\n"


/*非阻塞读终端*/
int main(void){
char buf[10];
int fd,n;
fd=open("/dev/tty",O_RDONLY|O_NONBLOCK);
if(fd<0){
perror("open file /dev/tty");
exit(1);
}
tryagain:
n=read(fd,buf,10);
if(n<0){
if(errno==EAGAIN){
sleep(1);
write(STDOUT_FILENO,MSG_TRY,strlen(MSG_TRY));
goto tryagain;
}
perror("read /dev/tty");
exit(1);
}
write(STDOUT_FILENO,buf,n);
close(fd);
return 0;
}




#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>


#define MSG_TRY "try again\n"
#define MSG_TIMEOUT "timeout\n"


/*非阻塞读终端和等待超时*/
int main(void){
char buf[10];
int fd,n,i;
fd=open("/dev/tty",O_RDONLY|O_NONBLOCK);
if(fd<0){
perror("open file /dev/tty");
exit(1);
}
for(i=0;i<5;i++){
n=read(fd,buf,10);
if(n>=0){
break;
}
if(errno!=EAGAIN){
perror("read /dev/tty");
exit(1);
}
sleep(1);
write(STDOUT_FILENO,MSG_TRY,strlen(MSG_TRY));
}
if(i==5){
write(STDOUT_FILENO,MSG_TIMEOUT,strlen(MSG_TIMEOUT));
}else{
write(STDOUT_FILENO,buf,10);
}
close(fd);
return 10;
}

你可能感兴趣的:(linux 系统编程学习笔记一)