2014025674(16) 《嵌入式系统程序设计》第七周学习总结

本周学习了第八章的主要内容主要包括两大部分分别为:

 

一、有名管道FIFO

1.有名管道说明

  • 定义:有名管道的出现突破了只能用于具有亲缘关系的进程之间,这就大大地限制了管道的使用限制,它可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出, 并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作, 使用非常方便。
  • 注意:FIFO 是严格地遵循先进先出规则的,对管道及 FIFO 的读总是从开始 处返回数据,对它们的写则把数据添加到末尾,它们不支持如 lseek()等文件定位操作。 有名管道的创建可以使用函数 mkfifo(),该函数类似文件中的 open()操作,可以指定管道的路径和打开的模式。
  • 对阻塞打开和非阻 塞打开的读写进行讨论:

          (1)对于读进程。

                  若该管道是阻塞打开,且当前 FIFO 内没有数据,则对读进程而言将一直阻塞到有数据写入。

                  若该管道是非阻塞打开,则不论 FIFO 内是否有数据,读进程都会立即执行读操作。即如果 FIFO 内没有数据,则读函数将立刻返回 0。

          (2)对于写进程。

                  若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。

                  若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。

2.mkfifo()函数格式

  •  mkfifo()函数语法要点

                                      

  • FIFO 相关的出错信息 

                                       

 

3.使用实例

  • 以下是写管道的程序:
/* fifo_write.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MYFIFO "/tmp/myfifo" /* 有名管道文件名*/
#define MAX_BUFFER_SIZE PIPE_BUF /*定义在于 limits.h 中*/
int main(int argc, char * argv[]) /*参数为即将写入的字符串*/
{
 int fd;
 char buff[MAX_BUFFER_SIZE];
 int nwrite;

 if(argc <= 1)
 {
 printf("Usage: ./fifo_write string\n");
 exit(1);
 }
 sscanf(argv[1], "%s", buff);

 /* 以只写阻塞方式打开 FIFO 管道 */
 fd = open(MYFIFO, O_WRONLY);
 if (fd == -1)
 {
 printf("Open fifo file error\n");
 exit(1);
 }
 /*向管道中写入字符串*/
 if ((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0)
 {
 printf("Write '%s' to FIFO\n", buff);
 }
 close(fd);
 exit(0);
}

 

  • 以下是读管道程序:
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#define MYFIFO "/tmp/myfifo" /* 有名管道文件名*/
#define MAX_BUFFER_SIZE PIPE_BUF /*定义在于 limits.h 中*/ 
int main()
{
 char buff[MAX_BUFFER_SIZE];
 int fd;
 int nread;
 /* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建*/
 if (access(MYFIFO, F_OK) == -1)
 {
 if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST))
 {
 printf("Cannot create fifo file\n");
 exit(1);
 }
 }
 /* 以只读阻塞方式打开有名管道 */
 fd = open(MYFIFO, O_RDONLY);
 if (fd == -1)
 {
 printf("Open fifo file error\n");
 exit(1);
 }

 while (1)
 {
 memset(buff, 0, sizeof(buff));
 if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0)
 {
 printf("Read '%s' from FIFO\n", buff);
 }
 }
 close(fd);
 exit(0);
}

  

 二、消息队列

1. 消息队列概述

  • 顾名思义,消息队列就是一些消息的列表。用户可以从消息队列中添加消息和读取消息等。从这点上看, 消息队列具有一定的 FIFO 特性,但是它可以实现消息的随机查询,比 FIFO 具有更大的优势。同时,这些消息又是存在于内核中的,由“队列 ID”来标识。

2. 消息队列的应用

(1)函数说明

消息队列的实现包括创建或打开消息队列、添加消息、读取消息和控制消息队列这 4 种操作。其中创建 或打开消息队列使用的函数是 msgget(),这里创建的消息队列的数量会受到系统消息队列数量的限制; 添加消息使用的函数是 msgsnd()函数,它把消息添加到已打开的消息队列末尾;读取消息使用的函数是 msgrcv(),它把消息从消息队列中取走,与 FIFO 不同的是,这里可以指定取走某一条消息;最后控制消息队列使用的函数是 msgctl(),它可以完成多项功能。

(2)函数格式

  • msgget()函数的语法要点。

                                             

  •  msgsnd()函数的语法要点。

                                             

                                              

 

3.使用实例

  • 消息队列发送端的代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFER_SIZE 512
struct message
{
 long msg_type;
 char msg_text[BUFFER_SIZE];
};
int main()
{
 int qid;
 key_t key;
 struct message msg;

 /*根据不同的路径和关键字产生标准的 key*/
 if ((key = ftok(".", 'a')) == -1)
 {
 perror("ftok");
 exit(1);
 }

 /*创建消息队列*/
 if ((qid = msgget(key, IPC_CREAT|0666)) == -1)
 {
 perror("msgget");
 exit(1);
 }
 printf("Open queue %d\n",qid);

 while(1)
 {
 printf("Enter some message to the queue:");
 if ((fgets(msg.msg_text, BUFFER_SIZE, stdin)) == NULL)
 {
 puts("no message"); 
 exit(1);
 }

 msg.msg_type = getpid();

 /*添加消息到消息队列*/
 if ((msgsnd(qid, &msg, strlen(msg.msg_text), 0)) < 0)
 {
 perror("message posted");
 exit(1);
 }

 if (strncmp(msg.msg_text, "quit", 4) == 0)
 {
 break;
 }
 }
 exit(0);
}
  • 以下是消息队列接收端
#include <sys/types.h>
#include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define BUFFER_SIZE 512 struct message { long msg_type; char msg_text[BUFFER_SIZE]; }; int main() { int qid; key_t key; struct message msg; /*根据不同的路径和关键字产生标准的 key*/ if ((key = ftok(".", 'a')) == -1) { perror("ftok"); exit(1); } /*创建消息队列*/ if ((qid = msgget(key, IPC_CREAT|0666)) == -1) { perror("msgget"); exit(1); } printf("Open queue %d\n", qid); do { /*读取消息队列*/ memset(msg.msg_text, 0, BUFFER_SIZE); if (msgrcv(qid, (void*)&msg, BUFFER_SIZE, 0, 0) < 0) { perror("msgrcv"); exit(1); } printf("The message from process %d : %s", msg.msg_type, msg.msg_text); } while(strncmp(msg.msg_text, "quit", 4)); /*从系统内核中移走消息队列 */ if ((msgctl(qid, IPC_RMID, NULL)) < 0) { perror("msgctl"); exit(1); } exit(0);

server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 4321
#define BUFFER_SIZE 1024
#define MAX_QUE_CONN_NM 5

int main()
{
 struct sockaddr_in server_sockaddr,client_sockaddr;
 int sin_size,recvbytes;
 int sockfd, client_fd;
 char buf[BUFFER_SIZE];
/*创建socket套接字接口*/
 sockfd = socket(AF_INET,SOCK_STREAM,0);
/*设置本地地址的相关参数*/
 server_sockaddr.sin_family = AF_INET;
 server_sockaddr.sin_port = htons(PORT);
 server_sockaddr.sin_addr.s_addr = INADDR_ANY;
 bzero(&(server_sockaddr.sin_zero),8);
/*允许重复使用本地地址与套接字进行绑定*/
 int i = 1;
 setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
/*绑定套接字和本地计算机*/
 bind(sockfd,(struct sockaddr *)&server_sockaddr,
 sizeof(struct sockaddr));
/*监听客户端连接*/
 listen(sockfd, MAX_QUE_CONN_NM);
/*接收客户端的连接请求*/
 client_fd = accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_size);
/*接收客户端的发送*/
 recvbytes = recv(client_fd, buf, BUFFER_SIZE, 0);
/*关闭窗口*/
 close(sockfd);
 exit(0);
}                                                                  

 


posted @ 2017-06-09 21:53  6班liran  阅读(338)  评论(0编辑  收藏  举报