课上实践补交

题目二要求:

学习使用stat(1),并用C语言实现

  1. 提交学习stat(1)的截图

  2. man -k ,grep -r的使用

  3. 伪代码

  4. 产品代码 mystate.c,提交码云链接

  5. 测试代码,mystat 与stat(1)对比,提交截图

问题探索与解决

首先学习stat(1)指令:使用指令man 1 stat

使用指令man -k stat



使用指令man -k stat | grep 2

伪代码:就是获取stat结构然后打印。

产品代码:

#include <sys/types.h>

#include <sys/stat.h>

#include <time.h>

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char *argv[])

       {

           struct stat sb;

           if (argc != 2) {

               fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);

               exit(EXIT_FAILURE);

           }

           if (stat(argv[1], &sb) == -1) {

               perror("stat");

               exit(EXIT_FAILURE);

           }

           printf("File type:                ");

           switch (sb.st_mode & S_IFMT) {

           case S_IFBLK:  printf("block device\n");            break;

           case S_IFCHR:  printf("character device\n");        break;

           case S_IFDIR:  printf("directory\n");               break;

           case S_IFIFO:  printf("FIFO/pipe\n");               break;

           case S_IFLNK:  printf("symlink\n");                 break;

           case S_IFREG:  printf("regular file\n");            break;

           case S_IFSOCK: printf("socket\n");                  break;

           default:       printf("unknown?\n");                break;

           }

           printf("I-node number:            %ld\n", (long) sb.st_ino);

           printf("Mode:                     %lo (octal)\n",

                   (unsigned long) sb.st_mode);

           printf("Link count:               %ld\n", (long) sb.st_nlink);

           printf("Ownership:                UID=%ld   GID=%ld\n",

                   (long) sb.st_uid, (long) sb.st_gid);

           printf("Preferred I/O block size: %ld bytes\n",

                   (long) sb.st_blksize);

           printf("File size:                %lld bytes\n",

                   (long long) sb.st_size);

           printf("Blocks allocated:         %lld\n",

                   (long long) sb.st_blocks);

           printf("Last status change:       %s", ctime(&sb.st_ctime));

           printf("Last file access:         %s", ctime(&sb.st_atime));

           printf("Last file modification:   %s", ctime(&sb.st_mtime));

           exit(EXIT_SUCCESS);

       }

stat指令与mystat测试比较:

2017-2018-1 20155302 课下实践IPC

共享内存

共享内存允许两个或多个进程共享一定的存储区,因为不需要拷贝数据,所以这是最快的一种IPC。

共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的地址空间(这里的地址空间具体是哪个地方?)中。其他进程可以将同一段共享内存连接到自己的地址空间中。所有进程都可以访问共享内存中的地址,就好像它们是malloc分配的一样。如果一个进程向共享内存中写入了数据,所做的改动将立刻被其他进程看到。

共享内存是IPC最快捷的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式则是需要将数据通过中间机制进行转换。共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅映射到各进程的地址不同而已,因此不需要进行复制,可以直接使用此段空间。

#include <sys/ipc.h>
#include <sys/shm.h>
(1)创建或访问共享内存
* int shmget(key_t key,size_t size,int shmflg); (2)附加共享内存到进程的地址空间
* void *shmat(int shmid,const void *shmaddr,int shmflg);//shmaddr通常为NULL,由系统选择共享内存附加的地址;shmflg可以为SHM_RDONLY (3)从进程的地址空间分离共享内存
* int shmdt(const void *shmaddr); //shmaddr是shmat()函数的返回值 (4)控制共享内存
* int shmctl(int shmid,int cmd,struct shmid_ds *buf);
* struct shmid_ds{
struct ipc_perm shm_perm;

};
cmd的常用取值有:(a)IPC_STAT获取当前共享内存的shmid_ds结构并保存在buf中(2)IPC_SET使用buf中的值设置当前共享内存的shmid_ds结构(3)IPC_RMID删除当前共享内存

代码实例:

建立共享内存并写入数据的程序

#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <errno.h>
void get_buf(char *buf)
{
int i=0;
while((buf[i]=getchar())!='\n'&&i<1024)
i++;
}
int main(void)
{
int shmid;
shmid=shmget(IPC_PRIVATE,sizeof(char)*1024,IPC_CREAT|0666);
if(shmid==-1)
{
perror("shmget");
}
char *buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
get_buf(buf);
printf("%d\n",shmid);
return 0;
}

读取数据的程序

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
int shmid;
shmid=atoi(argv[1]);
char *buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
printf("%s\n",buf);
shmdt(buf);
return 0;
}

管道

管道的特点:

1、管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;

2、只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。比如fork或exec创建的新进程,在使用exec创建新进程时,需要将管道的文件描述符作为参数传递给exec创建的新进程。当父进程与使用fork创建的子进程直接通信时,发送数据的进程关闭读端,接受数据的进程关闭写端。

3、单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

4、数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

(1)在两个程序之间传递数据的最简单的方法是使用popen()和pclose()函数:
#include <stdio.h>
FILE *popen(const char *command, const char *open_mode);
int pclose(FILE *stream);
popen()函数首先调用一个shell,然后把command作为参数传递给shell。这样每次调用popen()函数都需要启动两个进程;但是由于在Linux中,所有的参数扩展(parameter expansion)都是由shell执行的,这样command中包含的所有参数扩展都可以在command程序启动之前完成。 (2)pipe()函数:
#include <unistd.h>
int pipe(int pipefd[2]);
popen()函数只能返回一个管道描述符,并且返回的是文件流(file stream),可以使用函数fread()和fwrite()来访问。pipe()函数可以返回两个管道描述符:pipefd[0]和pipefd[1],任何写入pipefd[1]的数据都可以从pipefd[0]读回;pipe()函数返回的是文件描述符(file descriptor),因此只能使用底层的read()和write()系统调用来访问。pipe()函数通常用来实现父子进程之间的通信。 (3)命名管道:FIFO
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *fifo_name, mode_t mode);

代码实例:

read端

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#define PATH "./fifo"
#define SIZE 128
int main()
{
umask(0);
if (mkfifo (PATH,0666|S_IFIFO) == -1)
{
perror ("mkefifo error");
exit(0);
}
int fd = open (PATH,O_RDONLY);
if (fd<0)
{
printf("open fd is error\n");
return 0;
} char Buf[SIZE];
while(1){
ssize_t s = read(fd,Buf,sizeof(Buf));
if (s<0)
{
perror("read error");
exit(1);
}
else if (s == 0)
{
printf("client quit! i shoud quit!\n");
break;
}
else
{
Buf[s] = '\0';
printf("client# %s ",Buf);
fflush(stdout);
}
}
close (fd);
return 3;
}

write端

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h> #define PATH "./fifo"
#define SIZE 128
int main()
{
int fd = open(PATH,O_WRONLY);
if (fd < 0)
{
perror("open error");
exit(0);
} char Buf[SIZE];
while(1)
{
printf("please Enter#:");
fflush(stdout);
ssize_t s = read(0,Buf,sizeof(Buf));
if (s<0)
{
perror("read is failed");
exit(1);
}
else if(s==0)
{
printf("read is closed!");
return 1;
}
else{
Buf[s]= '\0';
write(fd,Buf,strlen(Buf));
}
}
return 0;
}

FIFO(命名管道)

管道和命名管道的区别:

对于命名管道FIFO来说,IO操作和普通管道IO操作基本一样,但是两者有一个主要的区别,在命名管道中,管道可以是事先已经创建好的,比如我们在命令行下执行

mkfifo myfifo

就是创建一个命名通道,我们必须用open函数来显示地建立连接到管道的通道,而在管道中,管道已经在主进程里创建好了,然后在fork时直接复制相关数据或者是用exec创建的新进程时把管道的文件描述符当参数传递进去。

一般来说FIFO和PIPE一样总是处于阻塞状态。也就是说如果命名管道FIFO打开时设置了读权限,则读进程将一直阻塞,一直到其他进程打开该FIFO并向管道写入数据。这个阻塞动作反过来也是成立的。如果不希望命名管道操作的时候发生阻塞,可以在open的时候使用O_NONBLOCK标志,以关闭默认的阻塞操作。

FIFO可以说是管道的推广,克服了管道无名字的限制,使得无亲缘关系的进程同样可以采用先进先出的通信机制进行通信。

管道和FIFO的数据是字节流,应用程序之间必须事先确定特定的传输"协议",采用传播具有特定意义的消息。

要灵活应用管道及FIFO,理解它们的读写规则是关键。

代码实例:

接收消息:

  #include                 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h> #define FIFO "/tmp/fifo.temp1"
#define MAXLINE 1024 int main(void)
{
int fifo, fd;
char buf[MAXLINE];
int len;
fd_set set;
struct timeval tv;
int i = 0; unlink(FIFO); //如果FIFO存在,就先删除
if ((fifo = mkfifo(FIFO, O_RDWR)) < 0) //产生一个有名管道
{
printf("mkfifo error: %s/n", strerror(errno));
return(0);
}
if ((fd = open(FIFO, O_RDWR)) < 0) //读写打开有名管道
{
printf("open error: %s/n", strerror(errno));
return(0);
}
FD_ZERO(&set);
FD_SET(fd, &set);
tv.tv_sec = 5;
tv.tv_usec = 0; //超时设置,超过5秒没有信息,就打印超时
while (1)
{
FD_SET(fd, &set);
if ((i = select(fd + 1, &set, NULL, NULL, &tv)) > 0)//检测管道是否信息
{
printf("receive data/n");
if (FD_ISSET(fd, &set))
{
len = read(fd, buf, MAXLINE);//读取信息
buf[len] = '/0';
printf("buf = %s/n", buf);
tv.tv_sec = atoi(buf);
tv.tv_usec = 0;
}
}
else if (i == 0)
{
tv.tv_sec = 5;
tv.tv_usec = 0;
printf("chaoshi/n");
}
else
printf("error/n");
} unlink(FIFO); //删除有名管道
return(0);
}

发消息:

  #include                 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h> #define FIFO "/tmp/fifo.temp1"
#define MAXLINE 1024 int main(void)
{
int fifo;
char buf[MAXLINE];
int len;
int i = 0; strcpy(buf, "10");
if ((fifo = open(FIFO, O_RDWR)) < 0) //读写打开有名管道
{
printf("mkfifo error: %s/n", strerror(errno));
return(0);
}
while (i < 10)
{
sprintf(buf, "%d", i + 1);
len = write(fifo, buf, strlen(buf)); //写入信息到管道中
printf("send len = %d/n", len);
sleep(i);
i++;
} return(0);
}

信号

信号是Unix/Linux系统在一定条件下生成的事件。信号是一种异步通信机制,进程不需要执行任何操作来等待信号的到达。信号异步通知接收信号的进程发生了某个事件,然后操作系统将会中断接收到信号的进程的执行,转而去执行相应的信号处理程序。

(1)注册信号处理函数
#include <signal.h>
/*typedef void (*sighandler_t)(int); sighandler_t signal(int signum,sighandler_t handler);*/
* void (*signal(int signum, void (*handler)(int)))(int); //SIG_IGN && SIG_DFL
* int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); (2)发送信号
#include <signal.h>
* int kill(pid_t pid,int sig); //#include <sys/types.h>
* int raise(int sig); //kill(getpid(),sig);
* unsigned int alarm(unsigned int seconds); //(#include <unistd.h>) seconds秒后,向进程本身发送SIGALRM信号。 (3)信号集
信号集被定义为:typedef struct {unsigned long sig[_NSIG_WORDS];} sigset_t;
* int sigaddset(sigset_t *set,int sig);
* int sigemptyset(sigset_t *set);

信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。

代码实例:

#include <signal.h>
#include <stdio.h> void int_handler(int signum)
{
printf("\nSIGINT signal handler.\n");
printf("exit.\n");
exit(-1);
} int main()
{
signal(SIGINT, int_handler);
printf("int_handler set for SIGINT\n"); while(1)
{
printf("go to sleep.\n");
sleep(60);
} return 0;
}

消息队列

消息队列是内核地址空间中的内部链表,通过linux内核在各个进程直接传递内容,消息顺序地发送到消息队列中,并以几种不同的方式从队列中获得,每个消息队列可以用IPC标识符唯一地进行识别。内核中的消息队列是通过IPC的标识符来区别,不同的消息队列直接是相互独立的。每个消息队列中的消息,又构成一个独立的链表。

消息队列克服了信号承载信息量少,管道只能承载无格式字符流。

消息队列保存在内核中,是一个由消息组成的链表。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
(1)创建或访问消息队列
* int msgget(key_t key,int msgflg); (2)操作消息队列
* int msgsnd(int msqid,const void *msg,size_t nbytes,int msgflg);
msg指向的结构体必须以一个long int成员开头,作为msgrcv()的消息类型,必须大于0。nbytes指的是msg指向结构体的大小,但不包括long int部分的大小
* ssize_t msgrcv(int msqid,void *msg,size_t nbytes,long msgtype,int msgflg);
如果msgtype是0,就返回消息队列中的第一个消息;如果是正整数,就返回队列中的第一个该类型的消息;如果是负数,就返回队列中具有最小值的第一个消息,并且该最小值要小于等于msgtype的绝对值。 (3)控制消息队列
* int msgctl(int msqid,int cmd,struct msqid_ds *buf);
* struct msqid_ds{
struct ipc_perm msg_perm;

};

代码实例:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define MAX_LINE 80
#define MY_MQ_ID 1233
/*消息结构体的一般形式如下:
typedef struct
{
long type; //用于存放消息代码,必须位于首位
char message[ LENGHT+1 ];
}MSG_TYPE_T;
*/
typedef struct
{
long type;
float fval;
unsigned int uival;
char strval[ MAX_LINE+1 ];
}MY_TYPE_T;
int main( )
{
int msgid,ret;
//create the message queue with the id MY_MQ_ID
msgid=msgget( MY_MQ_ID,0666|IPC_CREAT );
if( msgid>=0 )
printf( "Created a Message Queue,message queue identifier is %d\n",msgid );
//modify the size of message queue
struct msqid_ds buf;
ret=msgctl( msgid,IPC_STAT,&buf );
printf( "The origianl size of queue is %d\n",buf.msg_qbytes ); buf.msg_qbytes=4096;
ret=msgctl( msgid,IPC_SET,&buf );
if( ret==0 )
printf( "Size sucessfully changed for queue,message queue identifier is %d\n",msgid );
//send a message
MY_TYPE_T myMessage;
myMessage.type=1L; //消息的类型,msgrcv会用到
myMessage.fval=128.256;
myMessage.uival=512;
strncpy( myMessage.strval,"This is a test.\n",MAX_LINE );
ret=msgsnd( msgid,( struct msgbuf* )&myMessage,sizeof( MY_TYPE_T ),0 ); //0是消息旗标
if( ret!=-1 )
printf( "Message send successfully.\n" );
//read a message
MY_TYPE_T recMessage;
ret=msgrcv( msgid,( struct msgbuf* )&recMessage,sizeof(MY_TYPE_T),1,0 );//这个地方Message Type要和欲接受的消息类型相同
if( ret!=-1 )
{
printf( "\nRead a message from the queue\n" );
printf( "Message Type:%ld\n",recMessage.type );
printf( "Float value:%f\n",recMessage.fval );
printf( "Uint value:%d\n",recMessage.uival );
printf( "String value:%s\n",recMessage.strval );
}
//destroy a message queue
ret=msgctl( msgid,IPC_RMID,NULL );
if( ret!=-1 )
printf( "Message queue %d sucessfully removed.\n",msgid ); return 0;
}

# 2017-2018-1 20155302 课下实践IPC及课上补充的更多相关文章

  1. 20155326 第十周课下作业-IPC

    20155326 第十周课下作业-IPC 学习题目: 研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 共享内存 管道 FIFO 信号 消息队列 学习过程 -IPC ...

  2. 2017-2018-1 20155226 《信息安全系统设计基础》课下实践——实现mypwd

    2017-2018-1 20155226 <信息安全系统设计基础>课下实践--实现mypwd 1 学习pwd命令 输入pwd命令 发现他是给出当前文件夹的绝对路径. 于是 man 1 pw ...

  3. 第十周课下作业-IPC

    第十周课下作业-IPC 题目:研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 共享内存 管道 FIFO 信号 消息队列 共享内存 共享内存允许两个或多个进程进程共 ...

  4. 2017-2018-1 20155318 《信息安全系统设计基础》第九周课下实践——实现mypwd

    2017-2018-1 20155318 <信息安全系统设计基础>第九周课下实践--实现mypwd 相关知识 man -k 查找含有关键字的内容 与管道命令结合使用:man -k k1 | ...

  5. 2017-2018-1 20155320第十周课下作业-IPC

    2017-2018-1 20155320第十周课下作业-IPC 研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 共享内存 管道 FIFO 信号 消息队列 共享内存 ...

  6. 20155339 《信息安全系统设计》第十周课下作业-IPC

    20155339 <信息安全系统设计>第十周课下作业-IPC 共享内存 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的 ...

  7. 20155311高梓云补交的Mypc课下实践

    20155311高梓云补交的Mypc课下实践 老师,由于我自己的疏忽导致没有及时交上这次作业.这是我的代码和截图. ``` ```/**import java.io.; import java.lan ...

  8. 20155322 2017-2018-1《信息安全系统设计》第十周 课下作业-IPC

    20155322 2017-2018-1<信息安全系统设计>课下作业-IPC 作业内容 研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接. 共享内存 管 ...

  9. 20155219 第十周课下作业-IPC

    题目:研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 共享内存 管道 FIFO 信号 消息队列 1.共享内存 共享内存就是允许两个不相关的进程访问同一个逻辑内存. ...

随机推荐

  1. 【日常记录】Unity3D 中的 Surface Shader 是不支持在 Pass中使用的,因为自动生成了 Pass

    如题 搞了好久,一直报错: Shader error in 'custom_outline_effect': Parse error: syntax error, unexpected TOK_PAS ...

  2. phantomJs页面操作

    因为phantomjs能加载和操纵页面,它可以自动化地完美执行页面的各种操作. 操作文档: 脚本的被执行,就像它真的正在web 浏览器上运行一样. 下面的脚本,是读取元素id为myagent的文本内容 ...

  3. npm私有仓库搭建

    背景 Node.js开发本地项目,有时不同项目之间存在依赖,如果不想把项目发布到npm社区的仓库,则需要有自己本地的仓库. 有些公司采用的是内网开发,很多npm资源无法从内网去下载. sinopia( ...

  4. java:通过Calendar类正确计算两日期之间的间隔

    在开发Android应用时偶然需要用到一个提示用户已用天数的功能,从实现上来看无非就是持久化存入用户第一次使用应用的时间firstTime(通过SharedPreferences .xml.sqlit ...

  5. ORAchk-数据库健康检查好帮手

    ORAchk 之前被称为RACcheck,后来它的检查范围进行了扩展,改名为了ORAchk,它是在数据库系统进行健康检查的一个专用工具,这个工具主要用来检查软件的配置是否符合要求以及一些最佳实践是否被 ...

  6. 【matlab】 拉格朗日插值

    第一个函数  "lagrange1.m" 输入:X Y 与点x0 输出:插值函数对应函数值 y0 function y = lagrange1(X,Y,x0) n = length ...

  7. randint(1,100) s.add(n) 集合的去重复性

  8. 关于print缩不缩进%有else没else的影响

    关于print缩不缩进%有else没else的影响 if gender == "男": # = 赋值. == 判断print("上厕所")else: print ...

  9. 【1】python-正则表达式语法规范与案例

    正则表达式的用法与案例分析 2018-08-24 21:26:14 [说明]:该文主要为了随后复习和使用备查,由于做了word文档笔记,所以此处博文没有怎么排版,没放代码,以插入图片为主, 一.正则表 ...

  10. QT导入libcurl支持HTTPS

    对于我这种不会编译的人来说,必须找到已经编译好的DLL文件,以及头文件才能使用. 幸运的在这个网站https://stackoverflow.com/questions/28137379/libcur ...