Domain Socket

目录

一、基本介绍

二、C Demo

1、Stream Domain Socket

1.1 Client

1.2 Server

2、Datagram  Domain Socket

2.1 Client

2.2 Server

三、Java 应用


一、基本介绍

        Unix域套接字(Unix Domain Socket)是基于 socket  框架上发展出的一种 IPC 机制。它与网络套接字(TCP 或 UDP)不同。网络套接字可以在不同机器上的进程之间进行通信,Domain socket 只可用于 unix 或 linux 系统内部。

        Domain Socket 使用文件系统路径作为地址来标识通信的端点。通信双方可以通过在文件系统中创建一个特殊类型的文件来创建一个 Domain Socket。这个文件可以是一个普通文件,也可以是一个符号链接。两个进程可以通过打开这个文件并使用标准的 socket 读写操作来进行通信。

        Domain Socket 提供了一种可靠的、高性能的进程间通信方式。它避免了网络套接字中的一些开销(网络协议栈打包、拆包、校验和计算、排序等等),并且可以利用操作系统的内核缓冲区来实现高效的数据传输。因此,在同一台机器上的进程间进行通信时,Unix域套接字通常比网络套接字更快。

        IPC 将应用层数据从一个进程拷贝到另一个进程。IPC 机制本质上是可靠的通讯,而网络传输是不可靠,只能通过传输层或应用层来保证可靠性传输。UNIX Domain Socket 也提供面向流和面向数据包两种 API 接口,类似于 TCP 和 UDP,面向消息的 UNIX Domain Socket 也是可靠的,消息既不会丢失也不会顺序错乱。

二、C Demo

        与使用网络地址的 socket 不同,domain socket 绑定本机文件地址,而且 socket family 为 AF_UNIX(或AF_LOCAL),这区别于 AF_INET。

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

 /*
 family(域) : AF_UNIX 
 type : SOCK_STREAM/ SOCK_DGRAM : 
 protocol : 0
 */
 int socket(int domain, int type, int protocol)

1、Stream Domain Socket

1.1 Client

        发送一次消息与接收应答

#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="/tmp/ip.ipc";

int main()
{
    struct sockaddr_un uds_file;

    char buffer[BUFFER_SIZE] = "hello world";
    uds_file.sun_family = AF_UNIX;
    strcpy(uds_file.sun_path,filename);

    int 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 *)&uds_file,sizeof(uds_file)) < 0){
        printf("connect socket failed(%s)\n", strerror(errno));
        return -1;
    }

    send(sock_fd, buffer, BUFFER_SIZE, 0);
        // -------------
    int ret = recv(sock_fd, buffer, BUFFER_SIZE, 0);
    if(ret < 0){
        printf("recv failed\n");
    }
        printf("client receive %s\n", buffer);
    close(sock_fd);
    return 0;
}

1.2 Server

        接收客户端消息与应答,且每个客户端只服务一次。

#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>
#include <error.h>

#define MAX_CONNECT_NUM 2
#define BUFFER_SIZE 1024
const char filename[50] = "/tmp/ip.ipc";

int main()
{
    int fd = socket(AF_UNIX,SOCK_STREAM,0);
    if(fd < 0){
        printf("Request socket failed!\n");
        return -1;
    }
    // domain address
    struct sockaddr_un uds_file;
    uds_file.sun_family = AF_UNIX;
    // 防止该文件被其它进程使用
    unlink(filename);
    strcpy(uds_file.sun_path, filename);

    if(bind(fd, (struct sockaddr *)&uds_file, sizeof(uds_file)) < 0 ){
        printf("bind failed(%s)\n", strerror(errno));
        return -1;
    }

    if(listen(fd, MAX_CONNECT_NUM) < 0){
        printf("listen failed!\n");
        return -1;
    }

    char buffer[BUFFER_SIZE];
    while(1){
        bzero(buffer, BUFFER_SIZE);
        // 提取就绪socket连接,只服务一次就关闭(测试使用,实际开发中可以启动线程服务每个就绪的socket连接)
        int 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");
        }

		strcpy(buffer, "nice to meet you!");
        send(new_fd, buffer, BUFFER_SIZE, 0);

        printf("%s\n", buffer);

        close(new_fd);
        //break;
    }
    close(fd);
}

2、Datagram  Domain Socket

        Datagram Domain socket 适合单向传输,双向需要另外定义一个 socket。

2.1 Client

#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 SIZE 4096
#define COUNT 1000000

const char filename[50] = "/tmp/ip.ipc";

int main(int argc, char **argv)
{
    struct sockaddr_un ipc_file;
    memset(&ipc_file, 0, sizeof(struct sockaddr));
    ipc_file.sun_family = AF_UNIX;
    strcpy(ipc_file.sun_path, filename);

    // unix domain socket
    int uds = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (uds < 0)
    {
        printf("unix domain socket created failed\n");
        return -1;
    }

    printf("[client] : domain file name (%s)\n", filename);
    unsigned char buff[SIZE] = "Hello World";
    int res = sendto(uds, buff, SIZE, 0, (struct sockaddr *)&ipc_file, sizeof(struct sockaddr_un));
    if (res < 0)
    {
        printf("send failed\n");
    }
    printf("over\n");

    return 0;
}

2.2 Server

#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 SIZE 4097
#define COUNT 1000000
const char filename[50] = "/tmp/ip.ipc";

int main()
{
    // domain file
    struct sockaddr_un ipc_file;
    memset(&ipc_file, 0, sizeof(ipc_file));
    ipc_file.sun_family = AF_UNIX;
    unlink(filename);
    strcpy(ipc_file.sun_path, filename);

    // unix domain socket
    int uds = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (uds < 0)
    {
        printf("unix domain socket created failed\n");
        return -1;
    }
    // uds bind domain file
    if (bind(uds, (struct sockaddr *)&ipc_file, sizeof(ipc_file)) < 0)
    {
        printf("bind failed\n");
        return -1;
    }

    printf("[server] : domain file name (%s)\n", filename);
    // buff
    char buff[SIZE] = "";
    while ( 1 )
    {
        int size = recvfrom(uds, buff, SIZE, 0, NULL, NULL);
        if ( size < 0 )
        {
            printf("recv failed\n");
            break;
        }
        printf("recv--(%s)\n", buff);
    }
    printf("over\n");
    close(uds);

}

三、Java 应用

        Java 自 1.7 开始支持。下面例子从网上找的,不一定可以运行,仅作参考。

1、Server

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) {
        try {
            // 创建服务端Socket,并指定监听的端口
            ServerSocket serverSocket = new ServerSocket(8888);
            
            System.out.println("Server started, waiting for client connection...");
            
            // 接受客户端连接
            Socket clientSocket = serverSocket.accept();
            
            System.out.println("Client connected.");
            
            // 处理客户端请求
            // ...
            
            // 关闭连接
            clientSocket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2、Client

import java.io.IOException;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        try {
            // 创建客户端Socket,并指定服务器的地址和端口
            Socket socket = new Socket("localhost", 8888);
            
            // 发送数据到服务端
            // ...
            
            // 读取服务端的响应
            // ...
            
            // 关闭连接
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

        对于开发环境是 1.6 的,所以需要封装 C 动态库,java 层通过 JNI 进行调用。

public class DomainSocket {

    // stream domain socket
    public native int domain_socket();

    public native int bind(int fd, String sock_file);

    public native int listen(int fd, int max_num);

    public native int accept(int fd);

    public native int connect(int fd, String sock_file);

    public native int send(int fd, byte[] buffer, int len);

    public native int recv(int fd, byte[] buffer, int len);

    public native int close(int fd);

    public native String last_error();
}

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要出家当道士

打赏是不可能,这辈子都不可能

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值