进程间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;
}

 

posted @ 2017-11-09 10:27  *平凡*随风舞  阅读(655)  评论(0编辑  收藏  举报