zoukankan      html  css  js  c++  java
  • linux 单机跨进程通信

      一般来说通过网络通信(比如tcp,udp)或者共享内存的方式肯定可以实现跨进程通信,但现在这里要说的是比较偏但实用的几个方法:利用unix域通信(普通网络连接),利用unix域通信(socketpair通信),以及pipe方式。

    一. 利用unix域通信(普通网络连接)

      socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。UNIX域套接字与TCP套接字相比较,在同一台主机的传输速度前者是后者的两倍。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIXDomain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

      使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。 

      UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在 文件系统中的路径 ,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

    #include <stdlib.h> 
    #include <stdio.h>
    #include <unistd.h> 
    #include <errno.h> 
    #include <sys/types.h> 
    #include <sys/socket.h> 
    #include <netinet/in.h> 
    #include <sys/un.h>
    #include <string>
    using std::string;
    
    
    void serverService()
    {
        int listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
        if(listenfd == -1)
        {
            perror("create listen fd error.");
            exit(-1);
        }
    
        char pathname[] = "/tmp/my.sock";  
        unlink(pathname);//如果文件系统中已存在该路径名,bind将会失败。为此我们先调用unlink删除这个路径名,以防止它已经存在 
        struct sockaddr_un servAddr;  
        servAddr.sun_family = AF_UNIX;  
        strcpy(servAddr.sun_path, pathname);  
        if (bind(listenfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1) // 若成功会创建pathname文件 
            perror("bind error");  
        if (listen(listenfd, SOMAXCONN) == -1)  
            perror("listen error");  
    
        while (1)  
        {  
            int connfd = accept(listenfd, NULL, NULL);  
            if (connfd == -1)  
            {
                if(connfd==EINTR)
                    continue;
                perror("accept");
            }
            else
            {
                char buffer[] = "i am a boy.";
                write(connfd, buffer, sizeof(buffer));
                close(connfd);
            }
        } 
    }
    
    void clientService()
    {
        int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);  
        if (sockfd == -1)  
            perror("socket error");  
    
        char pathname[] = "/tmp/my.sock";  
        struct sockaddr_un servAddr;  
        servAddr.sun_family = AF_UNIX;  
        strcpy(servAddr.sun_path, pathname);  
        if (connect(sockfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)  
            perror("connect error");
    
        char buffer[512];
        read(sockfd, buffer, sizeof(buffer));
        printf("read data is [%s]", buffer);
        close(sockfd);
    }
    
    int main(int argc, char* argv[])
    {
        if(argc != 2)
        {
            perror("command error.");
            exit(-1);
        }
    
        string service(argv[1]);
        if(service == "client")
        {
            clientService();
        }
        else if(service == "server")
        {
            serverService();
        }
        else
        {
            perror("command error.");
            return -1;
        }
    
        return 0;
    }

    二. 利用unix域通信(socketpair通信)

      实际上socketpair 函数跟pipe 函数是类似的,也只能在同个主机上具有亲缘关系的进程间通信,但pipe 创建的匿名管道是半双工的,而socketpair 可以认为是创建一个全双工的管道。可参见nginx对此种通信的使用。

      函数原型:  int socketpair(int domain, int type, int protocol, int sv[2]); 

      由此可见,上述例子中的通过普通的网络连接建立的unix通信也可以使用这种方式进行。

    三. pipe通信

      pipe是半双工的,一端要么只能读,要么只能写,不能混用。

  • 相关阅读:
    HDU 2544 最短路
    HDU 3367 Pseudoforest
    USACO 2001 OPEN
    HDU 3371 Connect the Cities
    HDU 1301 Jungle Roads
    HDU 1879 继续畅通工程
    HDU 1233 还是畅通工程
    HDU 1162 Eddy's picture
    HDU 5745 La Vie en rose
    HDU 5744 Keep On Movin
  • 原文地址:https://www.cnblogs.com/foreverstars/p/6442476.html
Copyright © 2011-2022 走看看