UNIX Domain Socket

概述

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 */
};
  • 1
  • 2
  • 3
  • 4

服務端: 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
  • 1
  • 2
  • 3
  • 4

SOCK_STREAM(流) : 提供有序,可靠的雙向連接字節流。 可以支持帶外數據傳輸機制, 
無論多大的數據都不會截斷 
SOCK_DGRAM(數據報):支持數據報(固定最大長度的無連接,不可靠的消息),數據報超過最大長度,會被截斷.

  • 獲取到socket文件描述符之後,還要將其綁定一個文件上
 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd : 傳入sock的文件描述符
addr : 用sockaddr_un表示
addrlen : 結構體長度
  • 1
  • 2
  • 3
  • 4
struct sockaddr_un {
    sa_family_t sun_family; /* AF_UNIX */
    char sun_path[UNIX_PATH_MAX];   /* pathname */
};
  • 1
  • 2
  • 3
  • 4
  • 監聽客戶端的連接
int listen(int sockfd, int backlog);
sockfd : 文件描述符
backlog : 連接隊列的長度
  • 1
  • 2
  • 3
  • 接受客戶端的連接
int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
UDS不存在客戶端地址的問題,因此這裏的addr和addrlen參數可以設置爲NULL
  • 1
  • 2

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章