美文网首页我爱编程程序员
Linux下进程间通讯方式 - UNIX Domain Sock

Linux下进程间通讯方式 - UNIX Domain Sock

作者: 程序手艺人 | 来源:发表于2018-01-03 23:06 被阅读498次

    概述

    Linux下进程通讯方式有很多,比较典型的有套接字,平时比较常用的套接字是基于TCP/IP协议的,适用于两台不同主机上两个进程间通信, 通信之前需要指定IP地址. 但是如果同一台主机上两个进程间通信用套接字,还需要指定ip地址,有点过于繁琐. 这个时候就需要用到UNIX Domain Socket, 简称UDS,
    UDS的优势:

    • UDS传输不需要经过网络协议栈,不需要打包拆包等操作,只是数据的拷贝过程
    • UDS分为SOCK_STREAM(流套接字)和SOCK_DGRAM(数据包套接字),由于是在本机通过内核通信,不会丢包也不会出现发送包的次序和接收包的次序不一致的问题

    流程介绍

    如果熟悉Socket的话,UDS也是同样的方式, 区别如下:

    • UDS不需要IP和Port, 而是通过一个文件名来表示

    • domain 为 AF_UNIX

    • UDS中使用sockaddr_un表示

    struct sockaddr_un {
        sa_family_t sun_family; /* AF_UNIX */
        char sun_path[UNIX_PATH_MAX];   /* pathname */
    };
    

    服务端: socket -> bind -> listen -> accet -> recv/send -> close
    客户端: socket -> connect -> recv/send -> close

    函数介绍

    • 开始创建socket
     int socket(int domain, int type, int protocol)
     domain(域) : AF_UNIX 
     type : SOCK_STREAM/ SOCK_DGRAM : 
     protocol : 0
    

    SOCK_STREAM(流) : 提供有序,可靠的双向连接字节流。 可以支持带外数据传输机制,
    无论多大的数据都不会截断
    SOCK_DGRAM(数据报):支持数据报(固定最大长度的无连接,不可靠的消息),数据报超过最大长度,会被截断.

    • 获取到socket文件描述符之后,还要将其绑定一个文件上
     int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    sockfd : 传入sock的文件描述符
    addr : 用sockaddr_un表示
    addrlen : 结构体长度
    
    struct sockaddr_un {
        sa_family_t sun_family; /* AF_UNIX */
        char sun_path[UNIX_PATH_MAX];   /* pathname */
    };
    
    • 监听客户端的连接
    int listen(int sockfd, int backlog);
    sockfd : 文件描述符
    backlog : 连接队列的长度
    
    • 接受客户端的连接
    int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
    UDS不存在客户端地址的问题,因此这里的addr和addrlen参数可以设置为NULL
    

    Demo程序

    • uds-server.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/stat.h>
    #include<sys/socket.h>
    #include<sys/types.h>
    #include<sys/un.h>
    #include<errno.h>
    #include<stddef.h>
    #include<unistd.h>
    
    #define MAX_CONNECT_NUM 2
    #define BUFFER_SIZE 1024
    const char *filename="uds-tmp";
    
    int main()
    {
        int fd,new_fd,len,i;
        struct sockaddr_un un;
        fd = socket(AF_UNIX,SOCK_STREAM,0);
        if(fd < 0){
            printf("Request socket failed!\n");
            return -1;
        }
        un.sun_family = AF_UNIX;
        unlink(filename);
        strcpy(un.sun_path,filename);
        if(bind(fd,(struct sockaddr *)&un,sizeof(un)) <0 ){
            printf("bind failed!\n");
            return -1;
        }
        if(listen(fd,MAX_CONNECT_NUM) < 0){
            printf("listen failed!\n");
            return -1;
        }
        while(1){
            struct sockaddr_un client_addr;
            char buffer[BUFFER_SIZE];
            bzero(buffer,BUFFER_SIZE);
            len = sizeof(client_addr);
            //new_fd = accept(fd,(struct sockaddr *)&client_addr,&len);
            new_fd = accept(fd,NULL,NULL);
            if(new_fd < 0){
                printf("accept failed\n");
                return -1;
            }
            int ret = recv(new_fd,buffer,BUFFER_SIZE,0);
            if(ret < 0){
                printf("recv failed\n");
            }
            for(i=0; i<10; i++){
                printf(" %d",buffer[i]);
            }
            close(new_fd);
            break;
        }
        close(fd);
    }
    
    
    • uds-client.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/stat.h>
    #include<sys/socket.h>
    #include<sys/types.h>
    #include<sys/un.h>
    #include<errno.h>
    #include<stddef.h>
    #include<unistd.h>
    #define BUFFER_SIZE 1024
    const char *filename="uds-tmp";
    
    int main()
    {
        struct sockaddr_un un;
        int sock_fd;
        char buffer[BUFFER_SIZE] = {1,2,3};
        un.sun_family = AF_UNIX;
        strcpy(un.sun_path,filename);
        sock_fd = socket(AF_UNIX,SOCK_STREAM,0);
        if(sock_fd < 0){
            printf("Request socket failed\n");
            return -1;
        }
        if(connect(sock_fd,(struct sockaddr *)&un,sizeof(un)) < 0){
            printf("connect socket failed\n");
            return -1;
        }
        send(sock_fd,buffer,BUFFER_SIZE,0);
    
        close(sock_fd);
        return 0;
    }
    
    

    参考

    相关文章

      网友评论

        本文标题:Linux下进程间通讯方式 - UNIX Domain Sock

        本文链接:https://www.haomeiwen.com/subject/pyqcnxtx.html