UNIX Domain Socket IPC

目录

  • 目录
  • 概述
  • socket函数使用
    • struct sockaddr_un
    • socket
    • bind
    • listen
    • accept
    • connect
  • Socket IPC 实例
    • server
    • client
    • 运行结果

概述

socket API原本是为网络通讯设计的,但是后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。

虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:

  • 不需要经过网络协议栈。
  • 不需要打包拆包
  • 不需要计算校验和
  • 不需要维护序号和应答等

这是因为IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似TCP和UDP,但是面向流的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

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

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


socket函数使用

接下来,把UNIX Domain Socket编程用到的几个主要函数讲解一下。

struct sockaddr_un

UNIX Domain Socket使用的地址结构体定义如下:

#define UNIX_PATH_MAX 108

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

socket()

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

参数定义如下:

  1. domain指定socket的通信协议集(AF_UNIX和AF_INET等)

    • AF_UNIX(与AF_LOCAL和AF_FILE相同)只能够用于单一的unix的系统上,使用AF_UNIX会在系统上创建一个socket文件,不同进程通过读写这个文件来实现通信。
    • AF_INET则是用于网络的,所以可以允许远程主机之间的通信。
  2. type指定socket的类型(SOCK_STREAM和SOCK_DGRAM等)
    • SOCK_STREAM表明使用TCP协议,这就意味着会提供按顺序的、可靠、双向、面向连接的比特流。
    • SOCK_DGRAM表明使用UDP协议,这就意味着会提供定长的、不可靠、无连接的通信。
  3. protocol指定实际使用的传输协议。最常见的就是IPPROTO_TCP、IPPROTO_STCP、IPPROTO_UDP、IPPROTO_DCCP。如果该项为0,即根据选定的domain和type选择使用缺省协议。

调用socket()函数后,成功会返回文件描述符,失败则返回-1。


bind()

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

bind()为socket分配地址。当使用socket()创建套接字之后,仅仅赋予了其所使用的协议,而没有分配地址。在接受其它主机连接前,必须先调用bind()为socket分配地址。

参数定义如下:

  1. sockfd:这是socket的描述符。
  2. addr:指向sockaddr结构(用于表示所分配地址)的指针。
  3. addrlen:sockaddr结构的长度。

listen()

#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);

当socket和一个地址绑定后,调用listen()函数开始监听连接请求。但是,这只能在有可靠数据流保证时使用,如SOCK_STREAM。

参数定义如下:

  1. sockfd:socket的描述符。
  2. backlog:一个决定监听队列大小的整数,当有一个连接请求到来,就会进入此监听队列。当队列满后,新的连接请求就会返回错误。

如果监听成功返回0,否则返回-1。


accept()

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

当应用程序监听来自其他主机的面向数据流的连接时,通过事件(比如UNIX select()系统调用)通知它。必须用accept()函数初始化连接。accept()为每个连接创立新的套接字并从监听队列中移除这个连接。

参数定义如下:

  1. sockfd:监听的socket描述符。
  2. addr:指向sockaddr结构体的指针,客户端地址信息。
  3. addrlen:指向socklen_t的指针,确定客户端结构体的大小。

accpet成功返回新的套接字描述符,出错返回-1。进一步通信必须通过这个套接字。


connect()

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

connect()系统调用为一个套接字设置连接,参数有文件描述符和主机地址。


Socket IPC 实例

接下来,简单实现一个进程间通过UNIX Domain Socket进行通讯的参考实例。

server

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define QLEN 8

char *socket_path="wzy.socket";

int main(int argc, char **argv)
{
    int fd, clifd, n;
    struct sockaddr_un un;
    char buf[100];

    if (argc > 1) socket_path = argv[1];

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("socket error");
        exit(1);
    }

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strncpy(un.sun_path, socket_path, sizeof(un.sun_path) - 1);
    unlink(socket_path);

    if (bind(fd, (struct sockaddr *) &un, sizeof(un)) < 0) {
        perror("bind error");
        exit(1);
    }

    printf("UNIX Domain Socket bound\n");

    memset(&buf, 0, sizeof(buf));

    if (listen(fd, QLEN) < 0) {
        perror("listen error");
        exit(1);
    }

    while (1) {
        if ((clifd = accept(fd, NULL, NULL)) == -1) {
            perror("accpet error");
            continue;
        }

        while ((n = read(clifd, buf, sizeof(buf))) > 0) {
            printf("read %d bytes: %s\n", n, buf);
        }

        if (n == -1) {
            exit(-1);
        } else if (n == 0) {
            printf("END\n");
            close(clifd);
        }
    }

    return 0;
}

client

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

char *socket_path="wzy.socket";

int main(int argc, char **argv)
{
    int fd;
    struct sockaddr_un un;
    char buf[100];

    if (argc > 1) socket_path = argv[1];

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("socket error");
        exit(1);
    }

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strncpy(un.sun_path, socket_path, sizeof(un.sun_path) - 1);

    if (connect(fd, (struct sockaddr *) &un, sizeof(un)) < 0) {
        perror("connect error");
        exit(-1);
    }

    while (scanf("%s", buf) != EOF) {
        if (write(fd, buf, sizeof(buf)) < 0) {
            perror("write error");
            exit(-1);
        }
    }

    return 0;
}

运行结果

server监听客户端发送的数据:

client上传的数据如下:

时间: 2024-08-27 19:25:19

UNIX Domain Socket IPC的相关文章

ndk学习16: unix domain socket

一.UNIX Domain Socket 概念: UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC) 特点: 1. 它不需要经过网络协议栈,不需要打包拆包.计算校验和.维护序号和应答等 2. 只是将应用层数据从一个进程拷贝到另一个进程. 工作模式: SOCK_DGRAM     类似于UDP SOCK_STREAM    类似于TCP 用途: UNIX Domain Socket可用于两个没有亲缘关系的进程,是全双工的,是目前使用最广泛的IP

由一个简单需求到Linux环境下的syslog、unix domain socket

本文记录了因为一个简单的日志需求,继而对linux环境下syslog.rsyslog.unix domain socket的学习.本文关注使用层面,并不涉及rsyslog的实现原理,感兴趣的读者可以参考rsyslog官网.另外,本文实验的环境实在debian8,如果是其他linux发行版本或者debian的其他版本,可能会稍微有些差异. 需求: 工作中有一个在Linux(debian8)环境下运行的服务器程序,用python语言实现,代码中有不同优先级的日志需要记录,开发的时候都是使用pytho

unix domain socket示例一(SOCK_DGRAM)

unix domain socket 是IPC通信的一种方式,可用于与管理进程间通信,同时由和网络socket统一,所以很好管理,使用还是比较多.现举个例子: server.c 1 #include <stdio.h> 2 #include <string.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <sys/types.h> 6 #include <sys/socke

【转】PHP实现系统编程(四)--- 本地套接字(Unix Domain Socket)

原文:http://blog.csdn.net/zhang197093/article/details/78143687?locationNum=6&fps=1 -------------------------------------------------------------------------------------------------------------------------------------------------------- Socket API一开始是为了

Unix domain socket

Unix domain socket 原文:https://www.cnblogs.com/sparkdev/p/8359028.html UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC),它不需要经过网络协议栈,不需要打包拆包.计算校验和.维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程.UNIX Domain Socket有SOCK_DGRAM或SOCK_STREAM两种工作模式,类似于UDP和TCP,但是面向消息的UNIX

问题解决:psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket &quot;/var/run/postgresql/.s.PGSQL.5432&quot;?

错误提示: psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"? 出现该问题的很多,以下是目前碰到的几种情况,之后碰到继续补充: 1.删除了/tmp路径中的.s.PGSQL.5432 与.s.

UNIX DOMAIN SOCKET效率

关于UNIX DOMAIN SOCKET和普通udp socket的对比 在TX1(4核A57 1.7GHz)的板卡上进行测试,每个包大小设置为1024,全速收发,UDS的速度在90Mbps左右,UDP在120Mbps左右(略有丢包) CPU占用率,UDS比UDP低10%,但是实际上,如果码率相近时,CPU占用率是差不多的 下面是UDP的CPU占用: top - 08:44:46 up 3:04, 5 users, load average: 1.78, 1.70, 1.66 Threads:

[dev][socket] unix domain socket删除socket文件

问题 在使用unix domain socket的时候,bind之后,会在本地路径里 产生一个与path对应的socket文件. 如何正确的在用完socket之后,对其销毁呢? 方案 使用 unlink()函数手工删除. 见: https://stackoverflow.com/questions/34873151/how-can-i-delete-a-unix-domain-socket-file-when-i-exit-my-application syslogd的代码里就是这样干的: ht

redis性能测试tcp socket and unix domain

UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包.计算校验和.维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程.UNIX域套接字与TCP套接字相比较,在同一台主