Linux IPC: UNIX Domain Socket 基本用法

当前Linux IPC最常用的方法就是UNIX Domain Socket和TCP Socket了。TCP Socket的基本用法可以看:Linux Socket TCP通信基本用法。这两种IPC一个很大的区别就是:

  • TCP使用IP + Port来标记进程;
  • UNIX Domain Socket使用文件来标记进程;

由于上面差异,在Socket API标记地址的结构体也有所不同,Domain Socket的结构体是struct sockaddr_un,里面包含了一个文件路径,这个路径就是用来标记进程的。下面,用一个例子来说明:

服务端

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

#define SOCK_SERV "/root/server_sock"

int main()
{
    int fd, connfd, size, ret;
    struct sockaddr_un un;
    char buff[20] = {0};
    char *msg = "Welcome, client!\n";
    size_t msglen = strlen(msg) + 1;

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, SOCK_SERV);
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) goto fail;

    size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
    ret = bind(fd, (struct sockaddr *)&un, size) < 0;
    if (ret < 0) goto fail;

    ret = listen(fd, 10);
    if (ret < 0) goto fail;
    printf("server listen...\n");

    while (1) {
        socklen_t len = sizeof(un);
        connfd = accept(fd, (struct sockaddr *)&un, &len);
        if (connfd < 0) goto fail;

        printf("accept fd %d\n", connfd);
        recv(connfd, buff, sizeof(buff), 0);
        printf("recv %s", buff);
        send(connfd, msg, msglen, 0);
        printf("send %s", msg);
        close(connfd);
    }

    close(fd);
    return 0;

fail:
    perror("error");
    exit(1);
}

客户端

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

#define SOCK_CLI  "/root/client_sock"
#define SOCK_SERV "/root/server_sock"

int main()
{
    struct sockaddr_un un;
    int fd, len, ret;

    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) goto fail;

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, SOCK_CLI);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
    ret = bind(fd, (struct sockaddr *)&un, len);
    if (ret < 0) goto fail;

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, SOCK_SERV);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(SOCK_SERV);
    ret = connect(fd, (struct sockaddr *)&un, len);
    if (ret < 0) goto fail;

    char *msg = "Hi, server!\n";
    char buff[20] = {0};
    size_t msglen = strlen(msg) + 1;
    send(fd, msg, msglen, 0);
    printf("send msg: %s", msg);
    recv(fd, buff, sizeof(buff), 0);
    printf("recv msg: %s", buff);

    close(fd);
    return 0;

fail:
    perror("error");
    exit(1);
}

运行

一个简易的makefile如下,运行时在两个console窗口分别启动即可,注意如果socket文件历史已存在,就先删除掉。

CFLAGS = -Werror -Wall
COMPILE = $(CC) $^ $(CFLAGS) -o $@

.PHONY : all
all : server.bin client.bin

server.bin : server.c
    $(COMPILE)

client.bin : client.c
    $(COMPILE)

.PHONY : clean
clean :
    rm *.bin

就API的使用而言,Domain Socket和TCP Socket几乎差不多,甚至TCP Socket还更加方便一些,也方便以后跨主机扩展。就效率而言,本机TCP Socket通信,Linux做了很多优化,两者也差不了多少。所以个人还是倾向于用TCP进行IPC.

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值