进程间IPC通信学习,详解本地套接字
在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; }