Linux系统通信


信号

信号处理函数

捕获信号:sighandler_t signal(int signum, sighandler_t handler);

//当发生signum信号时,调用handler函数void (*sighandler_t)(int)

int kill(pid_t pid, int sig);

//向pid进程发送信号sig

int raise(int sig);

向当前进程发送信号sig

unsigned int alarm(unsigned int seconds);

//seconds后,向当前进程发送SIGALRM信号

信号集处理函数

信号如果被屏蔽,则记录在未处理信号集中 (排队的意思是指当前信号未处理完又来新的信号,则不做处理,直接屏蔽新来的信号)
  • 非实时信号(1~31),不排队
  • 实时信号(34~64),排队
信号集相关API(设置某个信号是否需要排队)
  • int sigemptyset(sigset_t *set);
    • 将信号集合初始化为0
  • int sigfillset(sigset_t *set);
    • 将信号集合初始化为1
  • int sigaddset(sigset_t *set,int signum);
    • 将信号集合某一位设置为1
  • int sigdelset(sigset_t *set,int signum);
    • 将信号集合某一位设置为0
  • int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
    • 使用设置好的信号集去修改信号屏蔽集
    • 参数how:
      • SIG_BLOCK:屏蔽某个信号(屏蔽集 | set)
      • SIG_UNBLOCK:打开某个信号(屏蔽集 & (~set))
      • SIG_SETMASK:屏蔽集 = set
    • 参数oldset:保存就的屏蔽集的值,NULL表示不保存

管道

匿名管道 PIPE(只能在父子进程间通信)

int pipe(int pipefd[2]);

//pipefd[0] 指管道的读取端,pipefd[1]指向管道的写端,管道建立时,父子进程都可以对管道进行读写。当父子进程都关闭管道的读写端时,管道就在内存中释放了。

在这里插入图片描述

int pipe_fd[2]; //定义一个数组 pipe_fd,在创建匿名管道后通过数组返回管道的文件描述符。

if (pipe(pipe_fd) < 0) //:调用 pipe() 创建一个匿名管道,创建成功则得到两个文件描述符 pipe_fd[0]、pipe_fd[1],否则返回-1。
{
	 printf("pipe create error\n");
	 exit(1);
}

if ((pid = fork()) == 0) //子进程中读
 {
 /* 子进程关闭写描述符,并通过使子进程暂停 3s 等待父进程已关闭相应的读描述符 */
	 close(pipe_fd[1]);
	real_read = read(pipe_fd[0], buf, MAX_DATA_LEN))//向管道内写buf中的数据,返回是否读取成功
	/* 关闭子进程读描述符 */
	close(pipe_fd[0]); //关闭子进程的管道读取端
	exit(0);
 }

else if (pid > 0)
{
/* 父进程关闭读描述符,并通过使父进程暂停 1s 等待子进程已关闭相应的写描述符 */
close(pipe_fd[0]); 


 if((real_write = write(pipe_fd[1], data, strlen(data))) != -1) //父进程中读取

 {
 printf("Parent write %d bytes : '%s'\n", real_write, data);
 }

 /* 关闭父进程写描述符 */
 close(pipe_fd[1]); //(8)
 /* 收集子进程退出信息 */
 waitpid(pid, NULL, 0); //(9)
 exit(0)

有名管道 PIPE

int mkfifo(const char * pathname,mode_t mode);

mkfifo() 会根据参数 pathname 建立特殊的 FIFO 文件,而参数 mode 为该文件的模式与权限。
mode 模式及权限参数说明:
• O_RDONLY:读管道。
• O_WRONLY:写管道。
• O_RDWR:读写管道。
• O_NONBLOCK:非阻塞。
• O_CREAT:如果该文件不存在,那么就创建一个新的文件,并用第三个参数为其设置权限。
• O_EXCL:如果使用 O_CREAT 时文件存在,那么可返回错误消息。这一参数可测试文件是
否存在

mkfifo(MYFIFO, 0666//调用 mkfifo() 函数创建一个命名管道。
//在一个进程中写入数据
fd = open(MYFIFO, O_WRONLY | O_CREAT, 0644);// 以只写阻塞方式打开 FIFO 管道。
nwrite = write(fd, buff, MAX_BUFFER_SIZE);
close(fd);

//在另一个进程中读取数据
fd = open(MYFIFO, O_RDONLY);//使用 open() 函数以只读阻塞方式打开命名管道。
nread = read(fd, buff, MAX_BUFFER_SIZE)
close(fd);

system-V IPC

消息队列、共享内存和信号量被统称为 system-V IPC

消息队列

int msgget(key_t key, int msgflg);

作用是创建或获取一个消息队列对象,返回qid

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

是将消息写入到消息队列

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int␣msgflg);

从标识符为 msqid 的消息队列读取消息并将消息存储到 msgp

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

设置或者获取消息队列的相关属性,可用于删除消息队列

struct message//消息体经典结构
{
	long msg_type;
	char msg_text[BUFFER_SIZE];
};

//在一个进程中创建消息队列并写入数据
qid = msgget((key_t)1234, IPC_CREAT|0666)//创建消息队列,creat表示没有key为1234的队列创建,有则直接返回对应的qid,0666表示消息队列的读写权限
msgsnd(qid, &msg, strlen(msg.msg_text), 0)//0 则表示:当消息队列满时,msgsnd() 函数将会阻塞

//在另一个进程中创建消息队列并读取入数据
qid = msgget((key_t)1234, IPC_CREAT|0666))
msgrcv(qid, (void*)&msg, BUFFER_SIZE, 0, 0)//第二个0表示 阻塞式接收消息,没有该类型的消息 msgrcv 函数一直阻塞等待
(msgctl(qid, IPC_RMID, NULL)

信号量

等待和发送信号,即 P 操作和 V 操作,锁行为就是 P 操作,解锁就是 V 操作,可以直接理解为 P 操作是申请资源,V 操作是释放资源。
int semget(key_t key, int nsems, int semflg);

int semop(int semid, struct sembuf *sops, size_t nsops);

int semctl(int semid, int semnum, int cmd, ...);
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) */
};

sem_id = semget((key_t)6666, 1, 0666 | IPC_CREAT); /* 创建一个信号量 */


/* 信号量初始化(赋值)函数 */
sem_union.val = init_value; /* init_value 为初始值 */
semctl(sem_id, 0, SETVAL, sem_union)

 /* P 操作函数 */
struct sembuf sops;
sops.sem_num = 0; /* 单个信号量的编号应该为 0 */
 sops.sem_op = -1; /* 表示 P 操作 */
 sops.sem_flg = SEM_UNDO; /* 若进程退出,系统将还原信号量 */
 }
semop(sem_id, &sops, 1)

/* V 操作函数 */
struct sembuf sops;
sops.sem_num = 0; /* 单个信号量的编号应该为 0 */
sops.sem_op = 1; /* 表示 V 操作 */
sops.sem_flg = SEM_UNDO; /* 若进程退出,系统将还原信号量 */
}
semop(sem_id, &sops, 1) 


 /* 从系统中删除信号量的函数 */
semctl(sem_id, 0, IPC_RMID, sem_union)

共享内存

int shmget(key_t key, size_t size, int shmflg);

void *shmat(int shmid, const void *shmaddr, int shmflg);

int shmdt(const void *shmaddr);

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

//在一进程中写入共享内存的数据
shmid = shmget((key_t)1234, 4096, 0644 | IPC_CREAT);
shm = shmat(shmid, (void*)0, 0);//将线程的虚拟地址映射到虚拟内存中
strncpy(shm, buffer, 4096);
shmdt(shm)//将内存与线程分离

//在另一进程中读取共享内存的数据
semid = semget((key_t)6666, 1, 0666|IPC_CREAT); /* 创建一个信号量 */

shm = shmat(shmid, 0, 0);//将共享内存连接到当前进程的地址空间,返回内存的地址
printf("You wrote: %s", shm)
shmdt(shm)
shmctl(shmid, IPC_RMID, 0)//释放虚拟内存

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值