您的位置:首页 > 编程语言

unix环境高级编程第三章习题的一些拙见

2016-06-04 23:45 225 查看
写在前面:自学apue,时间有限,这个系列都是抽时间写的,目前已经看到15章,现在从头做题,如有错误还请指教。

apue3.1:

write和read这样的函数都属于系统调用,这里具体所指的没有缓冲区是没有用户缓冲区,而不是指没有内核缓冲区,这里以我个人的认识认为,这里write和read将数据拷贝到缓冲区后并不直接写到文件中,而是等一定条件发生后才写进去,但是具体机制还需研究。同时这里也暴露了一个问题,每次进行I/O都需要进行系统调用,这无疑是对系统资源的一种浪费,所以这也为后来的标准I/O函数库的产生做了铺垫。

apue3.2:

先上代码:

#include "apue.h"
#include <stdio.h>
#include <fcntl.h>

int dup2_self (const int ofd , const int nfd) ;

int main () {
int fd;
int flag;

fd = open ("tempfile" , O_RDWR | O_CREAT | O_TRUNC);
flag = dup2(0 , fd);
write (fd , "hello\n" , 6);
}

int dup2_self (const int ofd , const int nfd) {
char *fdptr;
int openmax = sysconf (_SC_OPEN_MAX);
int tempfd;
int count = 0;
int fdarr[openmax];
int i;

if (ofd > openmax || nfd > openmax) {
fprintf (stderr , "the arguement error\n");
exit (1);
}

fdptr = malloc (30 * sizeof (char));
sprintf (fdptr , "/proc/%d/fd/%d" , getpid() , ofd);
if (access (fdptr , 0) < 0) {
fprintf (stderr , "the ofd is not open\n");
exit (2);
}
sprintf (fdptr , "/proc/%d/fd/%d" , getpid() , nfd);
if (access (fdptr , 0) < 0) {
fprintf (stderr , "the nfd is not open\n");
exit (3);
}

if (nfd == ofd)
return nfd;
close (nfd);

while (tempfd = dup (ofd)) {
if (tempfd == nfd)
break;
else
fdarr[count++] = tempfd;
}
printf ("%d\n" , nfd);
for ( i = 0 ; i < count ; i++)
close (fdarr [i]);
return nfd;
}


这段代码显然无法做到dup2的原子性,但是在功能上至少可以实现所需要的功能,当然可靠性我也没有非常多的验证,这个最近本的实现让我弄清楚了很多问题:第一——dup2的使用规则,其实就是将文件描述符和文件描述标志的关系去掉,重新引导到另外一个文件描述标志中上。第二——dup的使用方法,它总是返回最小的可用的文件描述符值,比如在这里nfd(这里我在linux上将这个值打印出来是3)已经close后,再dup后就直接还是3,可见close掉后还是可用的文件描述符。第三——如何查看一个进程所打开的文件描述符在/proc/pid/fd/#就可以。最后结果就是我往main中的fd
write的时候,它会在标准输出显示。

——————————————————————————————————————————————————分割线2016.6.1

apue3.3:



这里我可以很容易的看见dup的作用是将函数返回的文件标志指向和自己一样的文件表项,而open的作用是使得函数返回的描述符指向另外一个文件表项,但是两者都会指向同一个V节点,那么这两者有什么不同吗?答案是,文件表项中拥有文件状态标识,当前文件的偏移,也就是说,假设现在fd1 fd2 fd3都在文件开头位置,如果我向fd1中写入一定字节后,再向fd2写入一定字节那么fd2的字节会显示在fd1后面,这时我再向fd3中写一定字节后就会覆盖前两个描述符的字节。F_SETFD这里的作用是设置文件描述符标识,而这里只有一个值,FD_CLOEXEC,属于每个文件描述符的属性。而F_SETFL则是和文件状态标识有关系,这个值在文件表项当中的。所以很容易看出fcntl
fd1时F_SETFD只影响其自身。F_SETFL则影响fd1和fd2.

apue3.4:





这里我只给出两种情况最后的图,前者是fd的值为1时的情况,后者是fd的值为2的情况。具体原因不在赘述,能弄清dup2_self的实现,这种题目就是水到渠成。

——————————————————————————————————————————————————分割线2016.6.2

apue3.5:

这道题目是很有趣的一道题目,这个问题其实从根本上让我们认识清楚了shell命令行中的重定向到底是怎么进行的,其实就是修改标准输入输出,标准错误的文件描述符的指向,文件描述符指向shell制定的文件的文件表项。地一个例子是首先将标准输出指向outfile的文件表项,再将标准错误的指向标准输出的文件表项,其结果就是两者都指向了同一个文件表项就是outfile的文件表项。第二个例子,首先将标准错误的文件表项指向标准输出的文件表项,这一步之后两者都指向终端的标准输出,后面再将标准输出指向outfile文件的表项,其结果就是两者指向不同的文件表项。

apue3.6:

先上代码:

/*************************************************************************
> File Name: apue3_6.c
> Author: jeff zhu
> Mail: 908190355@qq.com
> Created Time: 2016年06月03日 星期五 12时53分05秒
************************************************************************/

#include "apue.h"
#include <fcntl.h>

//#define TEST_RD
#define TEST_WR

int main () {
int fd;
char buf[1024];
int n;
char flag[] = "write ok\n";

if ((fd = open ("testfile" , O_RDWR | O_APPEND)) < 0)
err_sys ("open error");
if (lseek (fd , 0 , SEEK_SET) < 0)
err_sys ("lseek error");

#ifdef TEST_RD
while ((n = read (fd , buf , 1024)) > 0)
if (write (STDOUT_FILENO , buf , n) != n)
err_sys ("write error");
if (n < 0)
err_sys ("write error");
#endif
#ifdef TEST_WR
if (write (fd , flag , strlen (flag)) != strlen (flag))
err_sys ("write error");
#endif
exit (0);
}


这个代码,书的作者的意图很明显,希望我们主要到这样的细节——O_APPEND的作用,书上答案的解释是,read可以任意用lseek函数指定,但是write函数即使使用lseek重新定位,但是仍然会自动定位到文件的末尾将只能的内容写到文件中。在我的代码中testfile是在当前文件夹中随意建的一个文件,里面有一定的内容。当进行读测试的时候可以直接将testfile文件中的内容读到屏幕上,而进行写测试的时候,却在文件尾显示"write ok",这个答案给的结果一样。这里我认为O_APPEND这样设计的原因,其实在书上3.11节已经给出了解释,这是为了多进程的考虑,当出现竞争条件的时候,这样的设计不至于出现进程之间相互覆盖的情况。

——————————————————————————————————————————————————分割线2016.6.3

写在后面:哈哈,第三章已经更新完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unix 编程 标准 io