首页 > 其他分享 >Unix domain socket 简介

Unix domain socket 简介

时间:2023-10-12 17:24:27浏览次数:82  
标签:domain socket Unix UNIX path include cliun

原文: https://www.cnblogs.com/sparkdev/p/8359028.html

 

Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信。socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
UNIX domain socket 是全双工的,API 接口语义丰富,相比其它 IPC 机制有明显的优越性,目前已成为使用最广泛的 IPC 机制,比如 X Window 服务器和 GUI 程序之间就是通过 UNIX domain socket 通讯的。
Unix domain socket 是 POSIX 标准中的一个组件,所以不要被名字迷惑,linux 系统也是支持它的。

下面通过一个简单的 demo 来理解相关概念。程序分为服务器端和客户端两部分,它们之间通过 unix domain socket 进行通信。

服务器端程序

下面是一个非常简单的服务器端程序,它从客户端读字符,然后将每个字符转换为大写并回送给客户端:

复制代码
#include <stdlib.h>  
#include <stdio.h>  
#include <stddef.h>  
#include <sys/socket.h>  
#include <sys/un.h>  
#include <errno.h>  
#include <string.h>  
#include <unistd.h>  
#include <ctype.h>   
 
#define MAXLINE 80  
 
char *socket_path = "server.socket";  
 
int main(void)  
{  
    struct sockaddr_un serun, cliun;  
    socklen_t cliun_len;  
    int listenfd, connfd, size;  
    char buf[MAXLINE];  
    int i, n;  
 
    if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {  
        perror("socket error");  
        exit(1);  
    }  
 
    memset(&serun, 0, sizeof(serun));  
    serun.sun_family = AF_UNIX;  
    strcpy(serun.sun_path, socket_path);  
    size = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path);  
    unlink(socket_path);  
    if (bind(listenfd, (struct sockaddr *)&serun, size) < 0) {  
        perror("bind error");  
        exit(1);  
    }  
    printf("UNIX domain socket bound\n");  
      
    if (listen(listenfd, 20) < 0) {  
        perror("listen error");  
        exit(1);          
    }  
    printf("Accepting connections ...\n");  
 
    while(1) {  
        cliun_len = sizeof(cliun);         
        if ((connfd = accept(listenfd, (struct sockaddr *)&cliun, &cliun_len)) < 0){  
            perror("accept error");  
            continue;  
        }  
          
        while(1) {  
            n = read(connfd, buf, sizeof(buf));  
            if (n < 0) {  
                perror("read error");  
                break;  
            } else if(n == 0) {  
                printf("EOF\n");  
                break;  
            }  
              
            printf("received: %s", buf);  
 
            for(i = 0; i < n; i++) {  
                buf[i] = toupper(buf[i]);  
            }  
            write(connfd, buf, n);  
        }  
        close(connfd);  
    }  
    close(listenfd);  
    return 0;  
} 
复制代码

简单介绍一下这段代码:

int socket(int family, int type, int protocol);

使用 UNIX domain socket 的过程和网络 socket 十分相似,也要先调用 socket() 创建一个 socket 文件描述符.
family 指定为 AF_UNIX,使用 AF_UNIX 会在系统上创建一个 socket 文件,不同进程通过读写这个文件来实现通信。
type 可以选择 SOCK_DGRAM 或 SOCK_STREAM。SOCK_STREAM 意味着会提供按顺序的、可靠、双向、面向连接的比特流。SOCK_DGRAM 意味着会提供定长的、不可靠、无连接的通信。
protocol 参数指定为 0 即可。
UNIX domain socket 与网络 socket 编程最明显的不同在于地址格式不同,用结构体 sockaddr_un 表示,网络编程的 socket 地址是 IP 地址加端口号,而 UNIX domain socket 的地址是一个 socket 类型的文件在文件系统中的路径,这个 socket 文件由 bind() 调用创建,如果调用 bind() 时该文件已存在,则 bind() 错误返回。因此,一般在调用 bind() 前会检查 socket 文件是否存在,如果存在就删除掉。
网络 socket 编程类似,在 bind 之后要 listen,表示通过 bind 的地址(也就是 socket 文件)提供服务。
接下来必须用 accept() 函数初始化连接。accept() 为每个连接创立新的套接字并从监听队列中移除这个连接。

客户端程序

下面是客户端程序,它接受用户的输入,并把字符串发送给服务器,然后接收服务器返回的字符串并打印:

复制代码
#include <stdlib.h>  
#include <stdio.h>  
#include <stddef.h>  
#include <sys/socket.h>  
#include <sys/un.h>  
#include <errno.h>  
#include <string.h>  
#include <unistd.h>  
 
#define MAXLINE 80  
 
char *client_path = "client.socket";  
char *server_path = "server.socket";  
 
int main() {  
    struct  sockaddr_un cliun, serun;  
    int len;  
    char buf[100];  
    int sockfd, n;  
 
    if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){  
        perror("client socket error");  
        exit(1);  
    }  
      
    // 一般显式调用bind函数,以便服务器区分不同客户端  
    memset(&cliun, 0, sizeof(cliun));  
    cliun.sun_family = AF_UNIX;  
    strcpy(cliun.sun_path, client_path);  
    len = offsetof(struct sockaddr_un, sun_path) + strlen(cliun.sun_path);  
    unlink(cliun.sun_path);  
    if (bind(sockfd, (struct sockaddr *)&cliun, len) < 0) {  
        perror("bind error");  
        exit(1);  
    }  
 
    memset(&serun, 0, sizeof(serun));  
    serun.sun_family = AF_UNIX;  
    strcpy(serun.sun_path, server_path);  
    len = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path);  
    if (connect(sockfd, (struct sockaddr *)&serun, len) < 0){  
        perror("connect error");  
        exit(1);  
    }  
 
    while(fgets(buf, MAXLINE, stdin) != NULL) {    
         write(sockfd, buf, strlen(buf));    
         n = read(sockfd, buf, MAXLINE);    
         if ( n < 0 ) {    
            printf("the other side has been closed.\n");    
         }else {    
            write(STDOUT_FILENO, buf, n);    
         }    
    }   
    close(sockfd);  
    return 0;  
}  
复制代码

与网络 socket 编程不同的是,UNIX domain socket 客户端一般要显式调用 bind 函数,而不依赖系统自动分配的地址。客户端 bind 一个自己指定的 socket 文件名的好处是,该文件名可以包含客户端的 pid 等信息以便服务器区分不同的客户端。

运行上面的程序

分别把服务器端程序和客户端程序保存为 server.c 和 client.c 文件,并编译:

$ gcc server.c -o server
$ gcc client.c -o client

先启动服务器端程序,然后启动客户端程序输入字符串并回车:

还不错,客户端得到了服务器端返回的大写字符串。接下来看看当前目录下的文件:

哈哈,多了两个 socket 文件。

总结

Unix domain socket 主要用于同一主机上的进程间通信。与主机间的进程通信不同,它不是通过 "IP地址 + TCP或UDP端口号" 的方式进程通信,而是使用 socket 类型的文件来完成通信,因此在稳定性、可靠性以及效率方面的表现都很不错。

标签:domain,socket,Unix,UNIX,path,include,cliun
From: https://www.cnblogs.com/jiftle/p/17759999.html

相关文章

  • 关于c语言操作libwebsockets示例
    第一步,安装libwebsockets库,c语言编写的,默认安装引用库,配置相应的库及路径第二步:上代码main.h ////CreatedbyAdministratoron2020/5/1.// #ifndefMEDIA_MAIN_H#defineMEDIA_MAIN_H #define boolchar volatileintexit_sig=0; #defineMAX_PAYLOAD_SIZE 10......
  • 14.2 Socket 反向远程命令行
    在本节,我们将继续深入探讨套接字通信技术,并介绍一种常见的用法,实现反向远程命令执行功能。对于安全从业者而言,经常需要在远程主机上执行命令并获取执行结果。本节将介绍如何利用_popen()函数来启动命令行进程,并将输出通过套接字发送回服务端,从而实现远程命令执行的功能。在实现......
  • linux socket地址
    socket地址://socket地址其实是一个结构体,封装端口号和IP等信息。后面的socket相关的API需要使用到这个socket地址。//客户端  -->  服务器(IP  、Port)通用socket地址:socket网络编程接口中表示socket地址是结构体sockaddr,其定义如下:(IPv4......
  • 封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类
    1.封装我们后续将使用c++来开发程序,因此有必要将用c写成的wss客户端、服务端程序作进一步封装,使其成为wss客户端类和服务端类,这样更便于调用。封装后的程序结构: ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class$tree .├──client│  ├──cl......
  • 14.1 Socket 套接字编程入门
    Winsock是Windows操作系统上的套接字API,用于在网络上进行数据通信。套接字通信是一种允许应用程序在计算机网络上进行实时数据交换的技术。通过使用Windows提供的API,应用程序可以创建一个套接字来进行数据通信。这个套接字可以绑定到一个端口,以允许其他应用程序连接它。另外,Winsoc......
  • jquery.form.js与file文件域、document.domain有冲突
    jquery.form.js的ajaxForm、ajaxSubmit方法无法成功执行回调函数:1.用response.getWriter().out()给客户端打印数据与<scripttype="text/javascript">document.domain="XXX.com";</script>使用jquery.form.js的ajaxForm、ajaxSubmit方法,......
  • SAP ABAP 域(domain)固定值读取方法
    1SELECTSINGLEVALPOS2FROMDD07V3INTO@DATA(GT_DD07V)4WHEREDOMNAME='ZSTUTYPE'ANDVALPOS=@P_ZSTUTYP."域名和值5IFSY-SUBRC<>0.6MESSAGETEXT-134TYPE'S'DISPLAYLIKE'E......
  • DDD(Domain-Driven Design,领域驱动设计)
    DDD(Domain-DrivenDesign,领域驱动设计)是一种软件开发方法论,它注重对业务领域的深入理解,并将领域模型作为软件设计的核心。在DDD中,领域模型是通过对业务领域的分析和抽象而得到的,它是对业务领域中的概念、规则、行为等的描述。领域模型的设计是DDD中的一个重要环节,它需要开发团队......
  • C++ libwebsockets搭建WebSocket服务端及Http客户端、服务端
    https://blog.csdn.net/fantasysolo/article/details/88908948  概念WebRTCWebRTC,名称源自网页即时通信(英语:WebReal-TimeCommunication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API。它于2011年6月1日开源并在Google、Mozilla、Opera支持下被纳入万维网联......
  • 8种品牌PLC单片机使用Socket编程实现以太网开放式通信服务器视频教程
    8种品牌PLC单片机使用Socket编程实现以太网开放式通信服务器视频教程一、罗克韦尔ABMicro850系列PLC实现ModbusTCP以太网通信协议​服务器视频教程:罗克韦尔ABMicro850系列PLC做ModbusTCP以太网通信服务器、以太网调试助手和ModbusPoll调试助手做ModbusTCP以太网通信客户端,......