1.信號
信號是比較復雜的通信方式,用于通知接收進程有某種事情發生,除了用于進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信息語義函數signal外,還支持語義符合Posix 1標準的信號函數sigaction。
- signal() 告訴系統內核怎么處理該信號
- sigaction() 也是處理信號,但比signal更健壯
- kill() 發送信號
- alarm() 經過預定時間后發送SIGALARM信號
2.mmap文件映射:
也是一種共享內存,但是它是直接映射到磁盤中具體的文件,會涉及到磁盤的讀寫和io占用,不如shm共享內存效率高,但因為它的實際存儲并沒有反映到內存上,可以申請比較大的存儲空間。
3.管道及有名管道
管道可用于具有親緣關系進程間的通信,例如父子進程,但是有名管道允許無關系的進程間通信。管道其實就是建立一個FIFO文件,一個進程往里面寫數據,另外的進程讀取數據。
demo如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main()
{
pid_t pid;
char buf[1024];
int fd[2];
char *p = "test for pipe\n";
if (pipe(fd) == -1)
sys_err("pipe");
pid = fork();
if (pid < 0)
{
sys_err("fork err");
}
else if(pid == 0)
{
//父進程
close(fd[1]);
int len = read(fd[0], buf, sizeof(buf));
write(STDOUT_FILENO, buf, len); //輸出到屏幕
close(fd[0]);
}
else
{
//子進程
close(fd[0]);
write(fd[1], p, strlen(p)); //寫入test for pipe
wait(NULL);
close(fd[1]);
}
return 0;
}
4.消息隊列
消息隊列也叫報文隊列,消息隊列是消息的鏈接表,包括Posix消息隊列和SystemV消息隊列,有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的信息,消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩沖區大小受限等缺點。
發送消息demo如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main(void)
{
int running = 1;
struct my_msg_st some_data;
int msgid = 0;
char buffer[BUFSIZ] = {0};
memset((void*)&some_data, 0, sizeof(some_data));
/*創建消息隊列*/
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error:%d\n",errno);
exit(EXIT_FAILURE);
}
/*循環向消息隊列中添加消息*/
while(running)
{
memset(buffer, 0, sizeof(buffer));
printf("Enter some text:");
fgets(buffer,BUFSIZ,stdin);
some_data.my_msg_type=1;
strcpy(some_data.some_text,buffer);
/*添加消息*/
if(msgsnd(msgid,(void *)&some_data,BUFSIZ,0)==-1)
{
fprintf(stderr,"msgsed failed\n");
exit(EXIT_FAILURE);
}
/*用戶輸入的為“end”時結束循環*/
if(strncmp(buffer,"end",3)==0)
{
running=0;
}
}
exit(EXIT_SUCCESS);
}
接收消息demo如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main(void)
{
int running=1;
int msgid = 0;
struct my_msg_st some_data;
long int msg_to_receive=0;
memset((void*)&some_data, 0, sizeof(some_data));
/*創建消息隊列*/
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
/*循環從消息隊列中接收消息*/
while(running)
{
/*讀取消息*/
if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1)
{
fprintf(stderr,"msgrcv failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
printf("接收到的消息為: %s",some_data.some_text);
/*接收到的消息為“end”時結束循環*/
if(strncmp(some_data.some_text,"end",3) == 0)
{
running=0;
}
}
/*從系統內核中移走消息隊列*/
if(msgctl(msgid,IPC_RMID,0) == -1)
{
fprintf(stderr,"msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
5.共享內存
共享內存是一種文件映射,使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其他通信機制,如信號量結合使用,來達到進程間的同步及互斥。
demo如下:
寫入共享內存:
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main(int argc, char *argv[])
{
int ret = 0;
int shmid = 0;
//創建共享內存 ,相當于打開文件,文件不存在則創建
shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget err");
return errno;
}
printf("shmid:%d \n", shmid);
Teacher *p = NULL;
//將共享內存段連接到進程地址空間
p = (Teacher*)shmat(shmid, NULL, 0);//第二個參數shmaddr為NULL,核心自動選擇一個地址
if (p == (void *)-1 )
{
perror("shmget err");
return errno;
}
strcpy(p->name, "aaaa");
p->age = 33;
//將共享內存段與當前進程脫離
shmdt(p);
printf("鍵入1 刪除共享內存,其他不刪除\n");
int num = 0;
scanf("%d", &num);
if (num == 1)
{
//用于控制共享內存
ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID為刪除內存段
if (ret < 0)
{
perror("rmerrr\n");
}
}
return 0;
}
從共享內存讀取:
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main(int argc, char *argv[])
{
int ret = 0;
int shmid = 0;
//打開獲取共享內存
shmid = shmget(0x2234, 0, 0);
if (shmid == -1)
{
perror("shmget err");
return errno;
}
printf("shmid:%d \n", shmid);
Teacher *p = NULL;
//將共享內存段連接到進程地址空間
p = (Teacher*)shmat(shmid, NULL, 0);
if (p == (void *)-1 )
{
perror("shmget err");
return errno;
}
printf("name:%s\n", p->name);
printf("age:%d \n", p->age);
//將共享內存段與當前進程脫離
shmdt(p);
printf("鍵入1 程序暫停,其他退出\n");
while(1)
{
sleep(1);
}
return 0;
}
6.socket
socket也就是套接字,最普遍的進程間通信機制,可用于不同機器之間的進程間通信,具體見網絡編程。