unix高级环境编程 例子 代码实现练习 第十四章:高级IO

程序清单 14-1 长的非堵塞write

/**
 * 程序清单 14-1 长的非堵塞write P357
 *
 * zy:
 * 可以运行,和书上类似。
 */
#include "apue.h"
#include "error.c"
#include <fcntl.h>
#include <errno.h>	//定义了通过错误码来回报错误资讯的宏
					//宏定义为一个int型态的左值, 包含任何函式使用errno功能所产生的上一个错误码
#include <fcntl.h>	//file control

char buf[500000];
void set_fl(int fd,int flags){//flags就是要准备打开的标志
    int val;

    if((val= fcntl(fd,F_GETFL,0))<0){
        err_sys("fcntl F_GETFL error");
    }
    val |=flags; //与标志表示打开一个

    if(fcntl(fd,F_SETFL,val)<0){
        err_sys("fcntl F_SETFL error");
    }
}
void clr_fl(int fd,int flags){//flags就是要关闭的标志
    int val;

    if((val= fcntl(fd,F_GETFL,0))<0){
        err_sys("fcntl F_GETFL error");
    }
    val &=~flags; //将这个标志关闭

    if(fcntl(fd,F_SETFL,val)<0){
        err_sys("fcntl F_SETFL error");
    }
}
int main(void){
	int ntowrite,nwrite;
	char *ptr;

	ntowrite=read(STDIN_FILENO,buf,sizeof(buf)); //STDIN_FILENO: Standard file descriptors 文件标识符
	fprintf(stderr,"read %d bytes\n",ntowrite); //stderr:Standard streams 应该是以流的形式

	set_fl(STDOUT_FILENO,O_NONBLOCK);

	ptr=buf;
	while(ntowrite>0){
		errno=0;
		nwrite=write(STDOUT_FILENO,ptr,ntowrite);
		fprintf(stderr,"nwrite = %d , errno = %d \n",nwrite,errno);

		if(nwrite>0){
			ptr+=nwrite;
			ntowrite-=nwrite;
		}
	}
	clr_fl(STDOUT_FILENO,O_NONBLOCK);
	exit(0);
}

程序清单 14-2  加锁和解锁一个文件区域的函数

/**
 * 程序清单 14-2  加锁和解锁一个文件区域的函数
 * zy:
 * 有了这几个函数就可以使用下面的宏定义了。

#define	read_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define	readw_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define	write_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define	writew_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define	un_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
 */
#include "apue.h"
#include "error.c"
#include <fcntl.h>

int lock_reg(int fd,int cmd, int type,off_t offset,int whence,off_t len){
	struct flock lock;
	lock.l_type=type;
	lock.l_start=offset;
	lock.l_whence=whence;
	lock.l_len=len;

	return (fcntl(fd,cmd,&lock));
}

程序清单 14-3 测试一个文件的锁的状态的函数

/**
 * 程序清单 14-3  测试一个文件的锁的状态的函数 P362
 * zy:
 * 可以使用下面的宏了
#define	is_read_lockable(fd, offset, whence, len) \
			(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define	is_write_lockable(fd, offset, whence, len) \
			(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)

 */
#include "apue.h"
#include "error.c"
#include <fcntl.h>

pid_t lock_test(int fd,int type,off_t offset,int whence,off_t len){
	struct flock lock;
	lock.l_type = type;
	lock.l_start = offset;
	lock.l_whence=whence;
	lock.l_len=len;

	if(fcntl(fd,F_GETLK,&lock)<0){
		err_sys("fcntl error");
	}
	if(lock.l_type==F_ULOCK){//没锁的话
		return 0;
	}

	return (lock.l_pid);	//有锁的话返回pid
}

程序清单 14-4 死锁检测实例

/**
 * 程序清单 14-4 死锁检测实例 P362
 * zy:
 * 很神奇
 * 我完全没看出这个tell_wait机制有作用,所以我把其注释了
 * 注释了之后代码还是正常运行,所以我认为tell_wait在这里是没用的
 * 而是系统自己的机制完成了释放另一个进程的拿到的锁的过程
asd@asd-desktop:~/workspace/test/src$ ./a.out
parent:got the lock, byte 1
child:got the lock, byte 0
child,writew_lock error: Resource deadlock avoided
parent:got the lock, byte 0
asd@asd-desktop:~/workspace/test/src$
 *
 */
#include "apue.h"
#include "error.c"
#include <fcntl.h>

#include <fcntl.h>

int lock_reg(int fd,int cmd, int type,off_t offset,int whence,off_t len){
	struct flock lock;
	lock.l_type=type;
	lock.l_start=offset;
	lock.l_whence=whence;
	lock.l_len=len;

	return (fcntl(fd,cmd,&lock));
}
static void lockabyte(const char *name,int fd, off_t offset){
	if(writew_lock(fd,offset,SEEK_SET,1)<0){
		err_sys("%s,writew_lock error",name);
	}
	printf("%s:got the lock, byte %ld\n",name,offset);
}
int main(void){
	int fd;
	pid_t pid;

	if((fd=creat("templock",FILE_MODE))<0){
		err_sys("creat error");
	}if(write(fd,"ab",2)!=2){
		err_sys("write error");
	}
	//TELL_WAIT();
	if((pid=fork())<0){
		err_sys("fork error");
	}else if(pid==0){
		lockabyte("child",fd,0);
		//TELL_PARENT(getppid());
		//WAIT_PARENT();
		lockabyte("child",fd,1);
	}else{
		lockabyte("parent",fd,1);
		//TELL_CHILD(pid);
		//WAIT_CHILD();
		lockabyte("parent",fd,0);
	}
	exit(0);
}

程序清单 14-5 在文件的整体上加锁

/**
 * 程序清单 14-5 在文件的整体上加锁 P365
 * zy:
 * 这里是完成在13-2中的一个函数,
 * 也就是守护进程对文件加锁
 *
 */
#include <unistd.h>
#include <fcntl.h>

int lockfile(int fd){
	struct flock fl;

	fl.l_type=F_WRLCK;
	fl.l_start=0;
	fl.l_whence=SEEK_SET;
	fl.l_len=0;
	return (fcntl(fd,F_SETLK,&fl));
}

程序清单 14-6 确定是否支持强制性锁机制

/**
 * 程序清单 14-6 确定是否支持强制性锁机制 P369
 * zy:
 * 看样子我的机子是支持强制性锁
 * 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out temp.lock
读锁试图锁上已经被父进程加了写锁的区域得到的错误代码:11
read Ok 强制性锁没有其作用,buf=ab
asd@asd-desktop:~/workspace/test/src$

 *
 */
#include "apue.h"
#include "error.c"
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
void set_fl(int fd,int flags){//flags就是要准备打开的标志
    int val;

    if((val= fcntl(fd,F_GETFL,0))<0){
        err_sys("fcntl F_GETFL error");
    }
    val |=flags; //与标志表示打开一个

    if(fcntl(fd,F_SETFL,val)<0){
        err_sys("fcntl F_SETFL error");
    }
}
void clr_fl(int fd,int flags){//flags就是要关闭的标志
    int val;

    if((val= fcntl(fd,F_GETFL,0))<0){
        err_sys("fcntl F_GETFL error");
    }
    val &=~flags; //将这个标志关闭

    if(fcntl(fd,F_SETFL,val)<0){
        err_sys("fcntl F_SETFL error");
    }
}
int lock_reg(int fd,int cmd, int type,off_t offset,int whence,off_t len){
	struct flock lock;
	lock.l_type=type;
	lock.l_start=offset;
	lock.l_whence=whence;
	lock.l_len=len;

	return (fcntl(fd,cmd,&lock));
}
int main(int argc, char **argv) {
	int fd;
	pid_t pid;
	char buf[5];
	struct stat statbuf;

	if(argc!=2){
		fprintf(stderr,"usage:%s filename\n",argv[0]);
		exit(1);
	}
	if((fd=open(argv[1],O_RDWR|O_CREAT|O_TRUNC,FILE_MODE))<0){
		err_sys("open error");
	}
	if(write(fd,"abcdef",6)!=6){
		err_sys("write error");
	}
	/*
	 * 开启强制性锁
	 */
	if(fstat(fd,&statbuf)<0){
		err_sys("fstat error");
	}
	if(fchmod(fd,(statbuf.st_mode & ~S_IXGRP)|S_ISGID)<0){
		err_sys("fchomd error");
	}
	//TELL_WAIT();

	if((pid=fork())<0){
		err_sys("fork error");
	}else if( pid>0){
		if(write_lock(fd,0,SEEK_CUR,0)<0){
			err_sys("write lock error");
		}
		//TELL_CHILD(pid);

		if(waitpid(pid,NULL,0)<0){
			err_sys("waitpid error");
		}
	}else{
		//WAIT_PARENT();
		set_fl(fd,O_NONBLOCK);

		/**
		 * 我们先上上锁,看看能得到什么
		 */
		if(read_lock(fd,0,SEEK_SET,0)!=-1){
			err_sys("child:read_lock succeeded");
		}
		printf("读锁试图锁上已经被父进程加了写锁的区域得到的错误代码:%d\n",errno);
		/**
		 * 但是我们还是试图去读
		 */
		if(lseek(fd,0,SEEK_SET)==-1){
			err_sys("lseek error");
		}
		if(read(fd,buf,2)<0){
			err_ret("read failed ,因为强制性锁在起作用\n");
		}else{
			printf("read Ok 强制性锁没有其作用,buf=%2.2s\n",buf);
		}
	}
	exit(0);
}

程序清单 14-7 检查描述符是否引用STREAMS设备

程序清单 14-8 测试isastream函数

/**
 * 程序清单 14-7 检查描述符是否引用STREAMS设备 P373
 * 程序清单 14-8 测试isastream函数 P373
 *
 * zy:
 * I_CANPPU试图改变属性,如果能改,则是一个stream
 *
 * 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out /dev/tty /dev/fd /dev/null /etc/motd
/dev/tty not a stream: Invalid argument
/dev/fd not a stream: Inappropriate ioctl for device
/dev/null not a stream: Inappropriate ioctl for device
/etc/motd not a stream: Inappropriate ioctl for device
asd@asd-desktop:~/workspace/test/src$


 */
#include <stropts.h>	//stropts.h - STREAMS interface
#include <unistd.h>
#include "apue.h"
#include <fcntl.h>
#include "error.c"

int isastream(int fd){
	return (ioctl(fd,I_CANPUT,0)!=-1);
}

int main(int argc, char **argv) {
	int i,fd;

	for(i=1;i<argc;i++){
		if((fd=open(argv[i],O_RDONLY))<0){
			err_ret("%s can't open",argv[i]);
			continue;
		}
		if(isastream(fd)==0){
			err_ret("%s not a stream",argv[i]);
		}else{
			err_msg("%s:stream device",argv[i]);
		}
	}
}

程序清单 14-9 列表留中的模块名

/**
 * 程序清单 14-9 列表留中的模块名 P375
 * zy:
 * 运行结果:
asd@asd-desktop:~/workspace/test/src$ who
asd      tty7         2014-03-20 09:13
asd      pts/0        2014-03-20 10:55 (:0.0)
asd@asd-desktop:~/workspace/test/src$ sudo ./a.out /dev/console
/dev/console is not a stream
asd@asd-desktop:~/workspace/test/src$ sudo ./a.out /dev/pts/0
/dev/pts/0 is not a stream
asd@asd-desktop:~/workspace/test/src$

 * 难道在我的机子上就不是一个STREAM设备?
 */
#include "apue.h"
#include <fcntl.h>
#include <stropts.h>
#include "error.c"

int main(int argc, char **argv) {
	int fd,i,nmods;

	struct str_list list;

	if(argc!=2){
		err_quit("usage:%s <pathname>",argv[0]);
	}
	if((fd=open(argv[1],O_RDONLY))<0){
		err_sys("can't open %s",argv[1]);
	}
	if(isastream(fd)==0){
		err_quit("%s is not a stream",argv[1]);
	}

	/*
	 * 看看有多少模块
	 */
	if((nmods=ioctl(fd,I_LIST,(void *)0))<0){
		err_sys("I_LIST error for nmods");
	}
	printf("#modelues=%d\n",nmods);

	/**
	 * 为模块名分配内存
	 */
	list.sl_modlist=calloc(nmods,sizeof(struct str_mlist));
	if(list.sl_modlist==NULL){
		err_sys("calloc error");
	}
	list.sl_nmods=nmods;

	/**
	 * 拿到所有的名字
	 */
	if(ioctl(fd,I_LIST,&list)<0){
		err_sys("I_LIST error for list");
	}
	/**
	 * 打印名字
	 */

	for(i=1;i<=nmods;i++){
		printf("%s : %s\n",(i==nmods)?"driver":"module",list.sl_modlist++->l_name);
	}
}

程序清单 14-10 用getmsg将标准输入复制到标准输出

/**
 * 程序清单 14-10 用getmsg将标准输入复制到标准输出 P378
 *
 * zy:
 * linux没有getmsg这个函数。不能运行
 * 我自己man了一下没找到。
http://bbs.csdn.net/topics/360039652
 */
#include "apue.h"
#include <stropts.h>
#include "error.c"
#define BUFFSIZE 4096

int main(int argc, char **argv) {
	int n,flag;
	char ctlbuf[BUFFSIZE],datbuf[BUFFSIZE];
	struct strbuf ctl,dat;

	ctl.buf=ctlbuf;
	ctl.maxlen=BUFFSIZE;
	dat.buf=datbuf;
	dat.maxlen=BUFFSIZE;

	for(;;){
		flag=0;
		if((n=getmsg(STDIN_FILENO,&ctl,&dat,&flag))<0){
			err_sys("getmsg error");
		}
		fprintf(stderr,"flag=%d,ctl.len=%d,dat.len=%d\n",flag,ctl.len,dat.len);
	}  if(dat.len==0){
		exit(0);
	} else if(dat.len>0){
		if(write(STDOUT_FILENO,dat.buf,dat.len)!=dat.len)
			err_sys("write error");
	}
}

 程序清单 14-11 readn和writen函数

/**
 * 程序清单 14-11 readn和writen函数 P390
 *
 * zy:
 * 读写指定量的数据,如果一次没有完成,那么会循环调用while来完成
 */
#include "apue.h"

ssize_t readn(int fd, void *ptr,size_t n){
	size_t nleft;
	ssize_t nread;

	nleft=n;
	while(nleft>0){
		if((nread=read(fd,ptr,nleft))<0){
			if(nleft==n){//这里是出错之后才会执行的语句
				return(-1);
			}else{
				break;
			}
		}else if(nread==0){
			break;
		}
		nleft-=nread;
		ptr +=nread;
	}
	return (n-nleft);
}
ssize_t writen(int fd, void *ptr,size_t n){
	size_t nleft;
	ssize_t nwritten;

	nleft=n;
	while(nleft>0){
		if((nwritten=write(fd,ptr,nleft))<0){
			if(nleft==n){//这里是出错之后才会执行的语句
				return(-1);
			}else{
				break;
			}
		}else if(nwritten==0){
			break;
		}
		nleft-=nwritten;
		ptr +=nwritten;
	}
	return (n-nleft);
}

程序清单 14-12 readn和writen函数

/**
 * 程序清单 14-12 用储存映射I/O复制文件 P394
 *
 * zy:
 * 用共享内存的方式完成了文件的复制
 * 运行结果:
asd@asd-desktop:~/workspace/test/src$ gcc test2.c
asd@asd-desktop:~/workspace/test/src$ sudo ./a.out core core2
asd@asd-desktop:~/workspace/test/src$ ll core core2
-rw-r----- 1 asd asd 4677632 Mar 18 20:06 core
-rw-r--r-- 1 asd asd 4677632 Mar 20 12:40 core2
asd@asd-desktop:~/workspace/test/src$
 */
#include "apue.h"
#include <fcntl.h>
#include <sys/mman.h>
#include "error.c"

int main(int argc, char **argv) {
	int fdin,fdout;
	void *src,*dst;
	struct stat statbuf;

	if(argc!=3){
		err_quit("usage: %s <from file> <to file>",argv[0]);
	}
	if((fdin=open(argv[1],O_RDONLY))<0){
		err_sys("can't open %s for reading",argv[1]);
	}
	if((fdout=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,FILE_MODE))<0){
			err_sys("can't create %s for writing",argv[2]);
	}
	if(fstat(fdin,&statbuf)<0){/*为了拿到被复制文件的长度*/
		err_sys("fstat error");
	}

	if(lseek(fdout,statbuf.st_size - 1,SEEK_SET)==-1){
		err_sys("lseek error");
	}
	if(write(fdout,"",1)!=1){
		err_sys("write error");
	}
	if((src=mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0))==MAP_FAILED){
		err_sys("mmap error for input");
	}
	if((dst=mmap(0,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fdout,0))==MAP_FAILED){
			err_sys("mmap error for output");
	}

	memcpy(dst,src,statbuf.st_size);
	exit(0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值