在linux中进程IPC通信机制总结
管道(pipe),存在于有血缘关系的进程间通信,是一种半双工的方式,数据只能单向流动
有名管道(fifo),存在于没有血缘关系进程间通信,伪文件,在磁盘上大小永远是0,在内核中有一个对应的缓冲区,同样也是半双工通信
内存映射区(mmap),将磁盘文件的数据映射到内存,通过修改内存就能修改磁盘文件,适用于有,或者无血缘关系进程间通信
信号(signal),较为复杂的一种方式,不但能给其它进程发送信号,同时也能给自身发送,用于通知有某种事件发生了
信号量(semaphore),主要用作同一进程与不同线程之间的同步手段
本地套接字(socket),可用于不同机器之间,不同进程的相互通信,稳定可靠。
以下是本地套接字TCP代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/un.h>
#define _SERVER_SOCK_ "sock.s"
int main(){
int sfd = socket(AF_UNIX,SOCK_STREAM,0);
struct sockaddr_un serv;
serv.sun_family = AF_LOCAL;
strcpy(serv.sun_path,_SERVER_SOCK_);
unlink(_SERVER_SOCK_);
if(bind(sfd,(struct sockaddr*)&serv,sizeof(serv)) < 0){
perror("bind err");
return -1;
}
listen(sfd,128);
struct sockaddr_un client;
socklen_t len = sizeof(client);
int epfd = epoll_create(1);
struct epoll_event ev,evs[10];
ev.events = EPOLLIN;
ev.data.fd = sfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&ev);
while(1){
int nready = epoll_wait(epfd,evs,10,-1);
int i;
for(i = 0;i<nready;i++){
//new conn
if(evs[i].data.fd == sfd){
if(evs[i].events & EPOLLIN){
int cfd = accept(sfd,(struct sockaddr*)&client,&len);
printf("new conn form %s---len%d\n",client.sun_path,len);
if(cfd > 0){
ev.data.fd = cfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);
}
}
}
else{
//read event
int connfd = evs[i].data.fd;
char buf[256] = {0};
int ret = recv(connfd,buf,sizeof(buf),0);
if(ret > 0){
printf("recv:%s",buf);
send(connfd,buf,ret,0);
}
else if(ret == 0){
printf("client close\n");
close(connfd);
ev.data.fd = connfd;
epoll_ctl(epfd,EPOLL_CTL_DEL,connfd,&ev);
}
}
}
}
close(sfd);
return 0;
}
UDP本地套接字方式:
//本地套接字UDP服务器端
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/un.h>
#include <errno.h>
#include <ctype.h>
#define _SERV_SOCK_ "sock.s" //服务器使用的本地套接字名
int main()
{
//创建套接字
int sfd = socket(AF_UNIX,SOCK_DGRAM,0);
//绑定套接字
struct sockaddr_un serv;
bzero(&serv,sizeof(serv));
serv.sun_family = AF_LOCAL;
strcpy(serv.sun_path,_SERV_SOCK_);
unlink(_SERV_SOCK_);
//bind 会创建本地套接字文件,如果套接字文件已经存在,会报错
if(bind(sfd,(struct sockaddr*)&serv,sizeof(serv)) < 0 ){
perror("bind err");
return -1;
}
char buf[256] = {0};
struct sockaddr_un client;
socklen_t len = sizeof(client);//为了recvfrom 准备变量
while(1){
//循环收发消息
int ret = recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&client,&len);
printf("recvfrom msg from %s ----\n",client.sun_path);
if(ret > 0){
//代表接收到数据
int i = 0;
for(i = 0 ; i < ret ; i ++){
buf[i] = toupper(buf[i]);
}
//发送给对方
sendto(sfd,buf,ret,0,(struct sockaddr*)&client,len);
}
else if (ret < 0){
perror("recvfrom err");
}
}
//4. 扫尾
close(sfd);
return 0;
}