目录
管道(pipe)
消息队列(message queue)
信号(signal)
套接字(socket)
在Linux系统中,进程是相互独立运行的,但是有时候需要不同进程之间进行通信,以实现数据共享和协作。Linux系统提供了多种进程间通信的方式,本文将详细介绍这些方式,并配以实例。
管道是一种最简单的进程间通信方式,它可以在一个进程中创建一个管道,然后将数据写入管道,另一个进程从管道中读取数据。管道分为有名管道和无名管道,无名管道只能在父子进程之间使用,而有名管道可以在不同进程之间使用。
重点:管道是最简单的进程间通信方式,可以在一个进程中创建一个管道,然后将数据写入管道,另一个进程从管道中读取数据。
注意事项:无名管道只能在父子进程之间使用,而有名管道可以在不同进程之间使用。同时管道的缓冲区大小有限,如果写入数据超过缓冲区大小,就会阻塞写入进程。
实例:
创建无名管道,父进程向子进程传递数据
#include
#include
#include
int main()
{
int fd[2];
pid_t pid;
char buf[1024];
if (pipe(fd) < 0) {
perror("pipe error");
exit(1);
}
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid > 0) {
close(fd[0]);
write(fd[1], "hello world\n", 12);
} else {
close(fd[1]);
read(fd[0], buf, 1024);
printf("%s", buf);
}
return 0;
}
消息队列是一种进程间通信的方式,它可以在不同进程之间传递数据,每个消息都有一个类型和一个数据,接收方可以按照类型接收数据。消息队列可以实现异步通信,发送方可以继续执行其他任务,而不必等待接收方接收数据。
重点:消息队列可以在不同进程之间传递数据,每个消息都有一个类型和一个数据,接收方可以按照类型接收数据。消息队列可以实现异步通信,发送方可以继续执行其他任务,而不必等待接收方接收数据。
注意事项:消息队列需要创建和删除,需要注意权限和安全问题。同时消息队列的大小有限,如果写入数据超过队列大小,就会出现消息丢失的情况。
实例:
创建消息队列,父进程向子进程发送消息
#include
#include
#include
#include
#include
struct msgbuf {
long mtype;
char mtext[1024];
};
int main()
{
int msgid;
pid_t pid;
struct msgbuf buf;
if ((msgid = msgget(IPC_PRIVATE, 0644)) == -1) {
perror("msgget error");
exit(1);
}
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid > 0) {
buf.mtype = 1;
sprintf(buf.mtext, "hello world");
msgsnd(msgid, &buf, sizeof(buf.mtext), 0);
} else {
msgrcv(msgid, &buf, sizeof(buf.mtext), 1, 0);
printf("%s\n", buf.mtext);
msgctl(msgid, IPC_RMID, NULL);
}
return 0;
}
共享内存是一种高效的进程间通信方式,它可以在不同进程之间共享同一块内存区域,从而实现数据共享。共享内存可以提高程序的执行效率,但是需要注意同步问题,以避免数据竞争。
重点:共享内存是一种高效的进程间通信方式,可以在不同进程之间共享同一块内存区域,从而实现数据共享。共享内存可以提高程序的执行效率,但是需要注意同步问题,以避免数据竞争。
注意事项:共享内存需要创建和删除,需要注意权限和安全问题。同时共享内存的大小有限,如果写入数据超过内存大小,就会出现数据覆盖的情况。
实例:
创建共享内存,父进程和子进程共享内存区域
#include
#include
#include
#include
int main()
{
int shmid;
pid_t pid;
char *ptr;
if ((shmid = shmget(IPC_PRIVATE, 1024, 0644)) == -1) {
perror("shmget error");
exit(1);
}
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid > 0) {
ptr = shmat(shmid, NULL, 0);
sprintf(ptr, "hello world");
shmdt(ptr);
} else {
ptr = shmat(shmid, NULL, 0);
printf("%s\n", ptr);
shmdt(ptr);
shmctl(shmid, IPC_RMID, NULL);
}
return 0;
}
信号是一种异步的进程间通信方式,它可以在不同进程之间传递信息,比如通知进程某个事件发生或者中断进程执行。信号可以实现简单的进程间通信,但是需要注意信号处理函数的编写,以保证程序的正确性。
重点:信号是一种异步的进程间通信方式,可以在不同进程之间传递信息,比如通知进程某个事件发生或者中断进程执行。信号可以实现简单的进程间通信,但是需要注意信号处理函数的编写,以保证程序的正确性。
注意事项:信号处理函数需要注意并发和同步问题,以保证程序的正确性。同时信号处理函数需要尽可能的简单,避免出现复杂的业务逻辑。
实例:
父进程向子进程发送SIGUSR1信号
#include
#include
#include
#include
void sig_handler(int signo)
{
if (signo == SIGUSR1) {
printf("received SIGUSR1\n");
}
}
int main()
{
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid > 0) {
sleep(1);
kill(pid, SIGUSR1);
} else {
signal(SIGUSR1, sig_handler);
while (1) {
sleep(1);
}
}
return 0;
}
套接字是一种进程间通信的方式,它可以在不同进程之间传递数据,比如网络通信和本地通信。套接字可以实现复杂的进程间通信,但是需要注意网络安全和性能问题。
重点:套接字是一种进程间通信的方式,可以在不同进程之间传递数据,比如网络通信和本地通信。套接字可以实现复杂的进程间通信,但是需要注意网络安全和性能问题。
注意事项:套接字需要创建和删除,需要注意权限和安全问题。同时套接字的传输速度受到网络带宽和延迟的影响,需要注意传输效率。
实例:
创建本地套接字,父进程向子进程发送数据
#include
#include
#include
#include
#include
int main()
{
int sockfd;
pid_t pid;
char buf[1024];
struct sockaddr_un addr;
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/test.sock");
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(1);
}
if (listen(sockfd, 5) == -1) {
perror("listen error");
exit(1);
}
if ((pid = fork()) < 0) {
perror("fork error");
exit(1);
} else if (pid > 0) {
close(sockfd);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
write(sockfd, "hello world", 12);
} else {
int connfd = accept(sockfd, NULL, NULL);
read(connfd, buf, 1024);
printf("%s\n", buf);
}
return 0;
}
总结:
Linux系统提供了多种进程间通信的方式,每种方式都有自己的特点和适用场景。在实际开发中,需要根据具体情况选择合适的进程间通信方式,以保证程序的正确性和高效性。