美文网首页
unix domain socket 的 UDP 通信

unix domain socket 的 UDP 通信

作者: Jamza | 来源:发表于2021-07-28 15:23 被阅读0次

什么是 Unix Domain Socket

一般将 socket 称为套接字,我们经常将 socket 指为网络通信的 socket,这些 socket 用于在网络中的不同设备之间的通信。但是 socket 也可以用于在同一台设备中(准确点,应该是同一 OS)的不用进程之间的通信,这样的 socket,被称为 unix domain socket

Unix Domain Socket 的特点

一般 unix domain socket 具有以下的特点:

  1. unix domain socket 比 TCP、IP 在本地通信更快,因为 unix domain socket 不经过网络协议栈,不需要打包、拆包、计算校验、维护序列号与应答等,只是将应用层数据从一个进程拷贝到另一个进程。
  2. unix domain socket 也提供面向流与面向数据包的 API 接口,分别类似于 TCP 与 UDP。但是面向数据包的 unix domain socket 也是可靠的,消息不会丢失,也不会乱序。
  3. unix domain socket 是全双工。

Unix Domain Socket 的 API

创建 unix domain socket 的套接字,也是使用函数 socket,但是与网络 socket 的入参有些不同,主要比较如下:

比较项 网络 socket Unix Domain Socket
地址族 AF_INET、PF_INET AF_UNIX
地址格式 sockaddr_in(表示 IP 地址与 port 端口) sockaddr_un(表示本地文件)
type SOCK_STREAM、SOCK_DGRAM、SOCK_RAW SOCK_STREAM、SOCK_DGRAM、SOCK_RAW

对于 unix domain socket,绑定的地址不是网络 socket 的 IP 地址与端口号的形式,而是形式上为文件系统中的一个文件,但是该文件不是普通类型的文件,不能进行普通文件的读写操作,不能使用文本编辑器打开编辑,只能以 socket 的方式对其进行读写操作。比如:

[root@vm_rp0_cpu0_docker ~]# ll /tmp/
total 0
srwxr-x---. 1 root root 0 May 19 10:02 omci_cli_log
srwxr-x---. 1 root root 0 May 19 09:57 omci_log

地址格式比较为:

struct sockaddr_in {
    sa_family_t sin_family;  /* address family, AF_INET */
    in_port_t   sin_port;    /* port in network byte order */
    struct in_addr sin_addr; /* internet address */
};

#define UNIX_PATH_MAX  108
struct sockaddr_un {
    sa_family_t  sin_family; /* address family, AF_UNIX */
    char sun_path[UNIX_PATH_MAX]; /* path name*/
};

对于路径名,分为两种,即普通路径名与抽象路径名。

  1. 普通路径名:是一个正常的字符串,也就是,sun_path 字段是以空字符结尾的绝对路径字符串;
  2. 抽象路径名:是 Linux 特有的一个特性,允许将一个 domain socket 绑定到一个名字上,而不会在文件系统中创建这个名字的 socket 文件。必须将 sun_path 的第一个字节设置为 NULL,即空字符,系统会将 sun_path 除了第一个字节之后余下的所有字节当作抽象名字,也就是说在解析抽象路径名时,需要用到 sun_path 中的所有字节。因为不会在文件系统中创建文件,对于抽象路径名来说,就不需要担心与文件系统中已经存在的文件产生名字冲突,也不需要在使用完套接字后删除附带的文件。当这个套接字被关闭后,系统自动删除这个抽象名。另外,抽象路径名还可以解决路径权限的问题。

Unix Domain Socket 的面向数据包的示例代码

服务端代码

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <iostream>
#include <unistd.h>

using namespace std;


char* server_file = "server.sock";

int main(int argc,char** argv)
{
    int fd = socket(AF_UNIX,SOCK_DGRAM,0);

    if (fd < 0)
    {
        perror("socket");
        return -1;
    }


    struct sockaddr_un addr;
    memset(&addr,0,sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path,server_file);

    if (access(addr.sun_path,0) != -1)
    {
        remove(addr.sun_path);
    }

    if(bind(fd,(sockaddr*)&addr,sizeof(addr)) < 0)
    {
        perror("bind");
        return -1;
    }


    struct sockaddr_un clientaddr;
    socklen_t len = sizeof(clientaddr);

    char msgrecv[1024];

  

    while (1)
    {
        memset(msgrecv,'\0',1024);
        int size = recvfrom(fd,msgrecv,sizeof(msgrecv),0,(sockaddr*)&clientaddr,&len);
        if (size < 0)
        {
            perror("recv");
            return -1;
        }


        cout << "I'm server,receive a msg: " << msgrecv  << " from: " << clientaddr.sun_path << endl;

        if (strncmp("quit",msgrecv,4) == 0)
        {
            cout << "Server is exiting!" << endl;
            break;
        }

        char *p = "OK,I got id!";
        int ssize = sendto(fd,p,strlen(p),0,(sockaddr*)&clientaddr,len);
        if (ssize < 0)
        {
            perror("sendto");
            return -1;
        }

        sleep(1);
    }


    if (close(fd) < 0)
    {
        perror("close");
        return -1;
    }

    return 0;
  
}


客户端代码


#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <iostream>
#include <unistd.h>

using namespace std;


char* server_file = "server.sock";
char* client_file = "client.sock";

int main(int argc,char** argv)
{
    int fd = socket(AF_UNIX,SOCK_DGRAM,0);

    if (fd < 0)
    {
        perror("socket");
        return -1;
    }


    struct sockaddr_un addr;
    memset(&addr,0,sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path,client_file);

    if (access(addr.sun_path,0) != -1)
    {
        remove(addr.sun_path);
    }

    if(bind(fd,(sockaddr*)&addr,sizeof(addr)) < 0)
    {
        perror("bind");
        return -1;
    }


    struct sockaddr_un clientaddr;
    socklen_t len = sizeof(clientaddr);

    char msgrecv[1024];
    struct sockaddr_un serveraddr;
    memset(&serveraddr,0,sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path,server_file);

  

    char *p = "Hello,how are you?";
    int ssize = sendto(fd,p,strlen(p),0,(sockaddr*)&serveraddr,len);
    if (ssize < 0)
    {
        perror("sendto");
        return -1;
    }

    int size = recvfrom(fd,msgrecv,sizeof(msgrecv),0,(sockaddr*)&serveraddr,&len);
    if (size < 0)
    {
        perror("recv");
        return -1;
    }

    cout << "I'm client,receive a msg :" << msgrecv << endl;

    sleep(2);

    char* goodbye = "quit";

    if (sendto(fd,goodbye,strlen(goodbye),0,(sockaddr*)&serveraddr,len) < 0)
    {
        perror("sendto");
        return -1;
    }



    if (close(fd) < 0)
    {
        perror("close");
        return -1;
    }

    return 0;
  
}

相关文章

网友评论

      本文标题:unix domain socket 的 UDP 通信

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