论坛网站模企业网站模板 html
memset 函数
作用:用于将一段内存的每个字节都填充成指定的数值。
函数格式
#include <string.h>
void *memset(void *s, int c, size_t n);
// 参数:
// s 是起始地址。
// c 每个字节的只
// n 长度
// 返回值: 返回 s 的值(地址)。
命名管道 FIFO
作用:用于非亲属关系之间的进程间的数据流通信。
mkfifo命令
mkfifo [管道文件名]
# 例如
mkfifo myf
创建管道的函数 myfifo
#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);
// 参数:
// pathname 文件路径
// mode 打开权限,如0644
打开命名管道的函数open
使用UNIX系统 open(2) 函数打开命名管道。open函数在建立管道前是阻塞函数。等待另外一端打开才向下继续执行。
读命名管道read(2),管道断裂时读取返回值为0
写命名管道write(2)
关闭命名管道close(2)
读取管道示例代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> #define FIFO_PATHNAME "./myfifo"int main(int argc, char * argv[]) {int fd;int ret;// 创建管道文件ret = mkfifo(FIFO_PATHNAME, 0666);printf("ret:%d\n", ret);// 打开管道文件printf("open....\n");fd = open(FIFO_PATHNAME, O_RDONLY);printf("open finished\n");if (-1 == fd) {perror("open");return 1;}while(1) {char buf[1024];ret = read(fd, buf, 1024);if ( ret == 0) {printf("写端已经退出,管道断裂\n");break;}buf[ret] = 0;if (0 == strcmp(buf, "exit"))break;printf("读取管道内容:%s\n", buf);}close(fd);return 0;
}
写入管道示例代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>#define FIFO_PATHNAME "./myfifo"int main(int argc, char * argv[]) {int fd;int ret;// 创建管道文件ret = mkfifo(FIFO_PATHNAME, 0666);printf("ret:%d\n", ret);// 打开管道文件fd = open(FIFO_PATHNAME, O_WRONLY);if (-1 == fd) {perror("open");return 1;}while(1) {char buf[1024];ret = read(0, buf, 1024);printf("read ret:%d\n", ret);if (0 == ret) {printf("用户没有输入任何信息,以ctrl + d 结束输入\n");} else {buf[ret-1] = 0; // 此处 最后的可能不是回车符号}write(fd, buf, ret);if (0 == strcmp(buf, "exit"))break;}close(fd);return 0;
}
示例:
写一个机器人程序 robot.c,使用命名管道 ./robotask和./robotanswer 进行通信。
客户端程序,main.c 读取键盘内容。发送给机器人,机器人给出答案并返回给客户端程序。如:
strtok
- 当机器人程序收到"hello" 时回复 "Hi";
- 当机器人程序收到"what is your name?" 时回复 "robot";
- 当机器人程序收到"exit" 时,机器人程序退出服务;
- 当机器人程序收到其他字符串时回复 "I don't know what you said!";
参考代码
机器人端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>// 机器人程序的客户端
#define FIFO_ROBOT_ASK "./fifoask"
#define FIFO_ROBOT_ANSWER "./fifoanswer"
#define BUF_SIZE (1024)void robot_answer(const char * ask, char * answer, int buf_len)
{if (0 == strcmp(ask, "hello"))strcpy(answer, "Hi");else if (0 == strcmp(ask, "what is your name?"))strcpy(answer, "robot");elsestrcpy(answer, "I don't know what you said!");
}int main(int argc, char * argv[]) {int fd_ask;int fd_answer;int ret;mkfifo(FIFO_ROBOT_ASK, 0666);mkfifo(FIFO_ROBOT_ANSWER, 0666);// 打开管道文件if ((fd_ask = open(FIFO_ROBOT_ASK, O_RDONLY)) < 0) {perror(FIFO_ROBOT_ASK);return 1;}if ((fd_answer = open(FIFO_ROBOT_ANSWER, O_WRONLY)) < 0) {perror(FIFO_ROBOT_ANSWER);return 2;}char buf_ask[BUF_SIZE];char buf_answer[BUF_SIZE];while(1) {ret = read(fd_ask, buf_ask, BUF_SIZE);if (0 == strcmp(buf_ask, "exit")) break;robot_answer(buf_ask, buf_answer, BUF_SIZE);write(fd_answer, buf_answer, strlen(buf_answer) + 1); // 写入了尾零}close(fd_ask);close(fd_answer);return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>// 机器人程序的客户端
#define FIFO_ROBOT_ASK "./fifoask"
#define FIFO_ROBOT_ANSWER "./fifoanswer"
#define BUF_SIZE (1024)int main(int argc, char * argv[]) {int fd_ask;int fd_answer;int ret;mkfifo(FIFO_ROBOT_ASK, 0666);mkfifo(FIFO_ROBOT_ANSWER, 0666);// 打开管道文件if ((fd_ask = open(FIFO_ROBOT_ASK, O_WRONLY)) < 0) {perror(FIFO_ROBOT_ASK);return 1;}if ((fd_answer = open(FIFO_ROBOT_ANSWER, O_RDONLY)) < 0) {perror(FIFO_ROBOT_ANSWER);return 2;}char buf_ask[BUF_SIZE];char buf_answer[BUF_SIZE];while(1) {char buf[1024];printf("你问:");fflush(stdout);ret = read(0, buf_ask, BUF_SIZE);buf_ask[ret-1] = 0;write(fd_ask, buf_ask, ret); // 写入了尾零if (0 == strcmp(buf_ask, "exit"))break;ret = read(fd_answer, buf_answer, BUF_SIZE);printf("机器人答:%s\n", buf_answer);}close(fd_ask);close(fd_answer);return 0;
}
System V IPC(XSI IPC)
- 消息队列
- 信号量
- 共享内存
命令 ipcs
ipcs--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息 ------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 连接数 状态
0x00000000 15 easthome 600 524288 2 目标
0x00000000 17 easthome 600 4194304 2 目标 --------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
查看 System V IPC 资源
消息队列(Message Queue)
消息队列相关的函数:msgget(2), msgctl(2),msgsnd(2), msgrcv(2)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>// 获取或创建消息队列
int msgget(key_t key, int msgflg);
// 参数:
// key 双方通信约定的整数值。
// msgflg(按位与):
// IPC_CREAT 创建
// IPC_EXCL 如果存在则报错
// 0666 权限位
// 返回值:消息队列的 ID(整数)。
创建可获取消息队列示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int main(int argc, char * argv[]) {key_t msg_id;// 创建消息队列,键值为1000msg_id = msgget(1000, IPC_CREAT|0666);if (msg_id < 0) {perror("msgget");return 1;}printf("msg_id:%d\n", msg_id);return 0;
}
向消息队列发送消息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>// 向消息队列发送(send)数据。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// 参数:
// msqid msgget返回的消息队列的id值。
// msgp: struct msgbuf 的结构体地址。
// msgsz: msgbuf中 mtext数据的长度。
// msgflg:发送选型,一般为0// 返回值:成功返回 0,失败返回 -1。struct msgbuf {//消息队列中数据的类型,必须大于 0long mtype; /* message type, must be > 0 */// 消息队列中的数据(可以为结构体)。char mtext[1]; /* message data */};
发送示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>struct msgbuf {long mtype; /* message type, must be > 0 */char mtext[1]; /* message data */
};#define BUF_SIZE (1024)int main(int argc, char * argv[]) {char buf[BUF_SIZE]; // 用于存储数据的缓冲区int type;struct msgbuf * msgp = (struct msgbuf*)buf;key_t msg_id;// 创建消息队列,键值为1000msg_id = msgget(1000, IPC_CREAT|0666);if (msg_id < 0) {perror("msgget");return 1;}printf("msg_id:%d\n", msg_id);// 循环向消息队列发送消息包while(1) {printf("请输入类型:");scanf("%d", &type);printf("请输入数据:");scanf("%s", msgp->mtext);// scanf("%s", &buf[8]);printf("您输入的类型是:%d, 数据是:%s\n",type, msgp->mtext);int mtext_len = strlen(msgp->mtext) + 1;msgp->mtype = type;// 发送消息int ret = msgsnd(msg_id, msgp, mtext_len, 0);printf("发送消息,ret:%d\n", ret);}// char buf[BUF_SIZE]; // 用于存储数据的缓冲区// int type;// struct msgbuf * msgp = (struct msgbuf*)buf;return 0;
}
接受消息队列的数据
// 从消息队列中接收(receive)数据。
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
// 参数:
// msqid msgget返回的消息队列的id值。
// msgp: 接受的 struct msgbuf 的结构体地址。
// msgsz: msgbuf中 mtext数据的的最大长度。
// msgtyp:接受消息的类型
// 大于1,接受某种类型的消息。
// 等于0,接受所有类型的消息(忽略类型)。
// 小于0,读取类型小于等于msgtyp 绝对值的类型// msgflg:接受选项,一般为0// 返回值:成功返回 数据长度。
接受消息队列的消息的数据示例代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>struct msgbuf {long mtype; /* message type, must be > 0 */char mtext[1]; /* message data */
};#define BUF_SIZE (1024)int main(int argc, char * argv[]) {char buf[BUF_SIZE]; // 用于存储数据的缓冲区int type;struct msgbuf * msgp = (struct msgbuf*)buf;key_t msg_id;// 创建消息队列,键值为1000msg_id = msgget(1000, IPC_CREAT|0666);if (msg_id < 0) {perror("msgget");return 1;}printf("msg_id:%d\n", msg_id);// 接收消息队列的消息包while(1) {int ret = msgrcv(msg_id, buf, (BUF_SIZE - sizeof(msgp->mtype)),1, // mtype类型0);printf("收到数据:ret:%d, mtype:%ld, mtext:%s\n",ret, msgp->mtype, msgp->mtext);}return 0;
}
发送消息队列的控制命令
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>// 发送消息队列的控制命令。
int msgctl(int msqid, int cmd, struct msqid_ds *buf);x
删除 消息队列示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>int main(int argc, char * argv[]) {int msg_id;// 创建消息队列,键值为1000msg_id = msgget(1000, 0666);if (msg_id < 0) {perror("msgget");return 1;}printf("msg_id:%d\n", msg_id);// 删除 消息队列int ret = msgctl(msg_id, IPC_RMID, NULL);printf("msgctl RMID ret:%d\n", ret);return 0;
}
ipcrm 命令
作用:移除某个 IPC 资源。
ipcrm [选项]
选项:-m, --shmem-id <id> 按 id 号移除共享内存段-M, --shmem-key <键> 按键值移除共享内存段-q, --queue-id <id> 按 id 号移除消息队列-Q, --queue-key <键> 按键值移除消息队列-s, --semaphore-id <id> 按 id 号移除信号量-S, --semaphore-key <键> 按键值移除信号量
ftok函数
作用:用于根据路径和一个常数值生成一个整数值用于作为ipc通信的键(Key)
#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
// 例如:
key_t msg_id = ftok("/etc/passwd", 25);
printf("%d\n", msg_id);
信号量数组(Semaphore)
作用:用于进程间协调工作。
信号量数组相关的函数有 semget(2),semctl(2),semop(2)
信号量数组的数据结构
semget函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);
// 参数:
// key: IPC 的键
// nsems 信号量数组的元素个数。
// semflg 创建选项。
对信号量进程操作的函数 semop(2)
作用:对信号量进程操作.
进程对信号量的增操作,会唤醒等待信号量的进程。
进程对信号量的减操作,如果减后的结果小于零,进程会阻塞(睡眠),直至信号量增加值可以减少的值。
int semop(int semid, struct sembuf *sops, size_t nsops);
semctl 函数
作用:对ipc通信的信号量进行控制。
int semctl(int semid, int semnum, int cmd, ...);
// 参数:
// semid 要操作的信号量
// semnum 信号量数组的第几个元素(信号量数组的下标)
// cmd 操作命令,如:
// IPC_GETVAL 获取某个信号量的值。
// IPC_SETVAL 设置某个信号量的值。
创建并设置信号量数组的示例代码
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>// 创建含有一个信号量的数组,并将其初始值设置成1
union semun {int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};int main(int argc, char * argv[]) {key_t sem_id;union semun arg;// 创建信号量sem_id = semget(1000, 1, IPC_CREAT|0664);if (-1 == sem_id) {perror("semget");return 1;}// 修改信号量数组中的初始值.int ret;// 设置信号量数组中索引为0 的初始为1arg.val = 1;ret = semctl(sem_id, 0, SETVAL, arg);printf("ret:%d\n", ret);printf("arg.val:%d\n", arg.val);// 获取信号两数组中索引为0 的信号两的初始值arg.val = 9999;ret = semctl(sem_id, 0, GETVAL);printf("ret:%d\n", ret);return 0;
}