跨进程通信: Unix Domain Socket 创建实例。 Windows和MacOS代码已适配兼容

跨进程通信: Unix Domain Socket 创建实例。 Windows和MacOS代码已适配兼容

一: 简介

具体使用到的Socket方法介绍可以查看 https://blog.csdn.net/goldWave01/article/details/135770238

本文中的 serverclient 的代码可以直接 复制粘贴到 Windows 或 MacOS 的命令行程序中直接运行。

由于 Windows 平台下的 Unix Domain Socket 创建文章比较少,所以创建了这个demo。可直接在跨平台程序中使用。

二:Demo 展示

分别创建了两个命令行程序,分别为 ServerClient
都各自发送和接收了一条消息后退出程序

  • MacOS 控制台打印如下:
    在这里插入图片描述
  • Windows控制台打印如下:
    在这里插入图片描述

三:代码

1. Server 代码

//
//  main.cpp
//  UDS_Server_cmd
//
//  Created by jimbo on 2024/1/23.
//

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#ifdef _WIN32
#include <system_error>
#include <WS2tcpip.h>
#include <afunix.h>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#endif // _WIN32

std::string s_sock_path;

#ifdef _WIN32
class  SocketInit
{
public:
    SocketInit() {
        WSADATA data;
        int ret = WSAStartup(MAKEWORD(2, 1), &data);
        printf("WSAStartup val:%d
", ret);
    }
    ~SocketInit() {
        printf("~SocketInit
");
        WSACleanup();
    }
};
const SocketInit sInit;
#endif // _WIN32

// 创建临时 sock 文件
/*
win: C:UsersADMINI~1AppDataLocalTempjimbo_uds_test.sock
mac: /tmp/jimbo_uds_test.sock

*/
static void getScokTempPath() {

#ifdef _WIN32
    wchar_t path[MAX_PATH + 1]{};
    ::GetTempPathW(_countof(path), path);

    char sock_path_c[MAX_PATH + 1];
    wcstombs(sock_path_c, path, MAX_PATH + 1);

    std::string std_path(sock_path_c);
    std_path += "jimbo_uds_server.sock";

    s_sock_path = std_path;
#else
    s_sock_path = "/tmp/jimbo_uds_test.sock";
#endif // _WIN32
        printf("tmp path:%s
", s_sock_path.c_str());

    //server 每次启动都要删除旧文件
    if (remove(s_sock_path.c_str()) == -1 && errno != ENOENT)
    {
        printf("remove file failed.
");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char* argv[]) {

    printf("
this is server!

");
    
    getScokTempPath();

    int client_fd;

    client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_fd < 0) {
        perror("socket connect failed");
        exit(EXIT_FAILURE);
    }




    struct sockaddr_un addr = { 0 };
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, s_sock_path.c_str());

    int ret = bind(client_fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un));
    if (ret < 0) {
        perror("socket bind failed");
        exit(EXIT_FAILURE);
    }

    printf("bind succeed!
");

    ret = listen(client_fd, 5);
    if (ret < 0) {
        perror("socket listen failed");
        exit(EXIT_FAILURE);
    }

    printf("listen succeed!
");

    printf("waiting client....
");
    client_fd = accept(client_fd, NULL, NULL);
    printf("client connect succeed!
");

    char buf[1024];
    if (recv(client_fd, buf, 1024, 0) < 0) {
        perror("socket recv failed");
        exit(EXIT_FAILURE);
    }
    printf("server recv response: [%s]
", buf);

    char buf1[] = "hello client, this msg is from server!";
    if (send(client_fd, buf1, sizeof(buf1), 0) < 0) {
        perror("socket send failed");
        exit(EXIT_FAILURE);
    }
    printf("server send msg succeed!
");

#ifdef _WIN32
    /* 关闭socket */
    closesocket(client_fd);
#else
    /* 关闭socket */
    close(client_fd);
#endif // _WIN32


    printf("server ended successfully
");
    exit(EXIT_SUCCESS);
}

2. Client 代码

//
//  main.cpp
//  Uds_Client_cmd
//
//  Created by jimbo on 2024/1/23.
//

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#ifdef _WIN32
#include <system_error>
#include <WS2tcpip.h>
#include <afunix.h>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#endif // _WIN32

std::string s_sock_path;

#ifdef _WIN32
class  SocketInit
{
public:
    SocketInit() {
        WSADATA data;
        int ret = WSAStartup(MAKEWORD(2, 1), &data);
        printf("WSAStartup val:%d
", ret);
    }
    ~SocketInit() {
        printf("~SocketInit
");
        WSACleanup();
    }
};
const SocketInit sInit;
#endif // _WIN32

// 创建临时 sock 文件
/*
win: C:UsersADMINI~1AppDataLocalTempjimbo_uds_test.sock
mac: /tmp/jimbo_uds_test.sock

*/
static void getScokTempPath() {

#ifdef _WIN32
    wchar_t path[MAX_PATH + 1]{};
    ::GetTempPathW(_countof(path), path);

    char sock_path_c[MAX_PATH + 1];
    wcstombs(sock_path_c, path, MAX_PATH + 1);

    std::string std_path(sock_path_c);
    std_path += "jimbo_uds_server.sock";

    s_sock_path = std_path;
#else
    s_sock_path = "/tmp/jimbo_uds_test.sock";
#endif // _WIN32

        printf("tmp path:%s
", s_sock_path.c_str());
}


int main(int argc, char* argv[]) {

    printf("
this is client!

");
    
    getScokTempPath();

    int client_fd;

    client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_fd < 0) {
        perror("socket create failed");
        exit(EXIT_FAILURE);
    }
    struct sockaddr_un addr  = {0};
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, s_sock_path.c_str());

    int ret = connect(client_fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un));
    if (ret < 0) {
        perror("socket connect failed");
        exit(EXIT_FAILURE);
    }

    printf("connect succeed!
");

    char sendBuf[] = "hello server, this msg is from client!";
    if (send(client_fd, sendBuf, sizeof(sendBuf), 0) < 0) {
        perror("socket send failed");
        exit(EXIT_FAILURE);
    }
    printf("send succeed!
");

    char recvBuf[1024];
    if (recv(client_fd, recvBuf, 1024, 0) < 0) {
        perror("socket recv failed");
        exit(EXIT_FAILURE);
    }
    printf("client recv response: [%s]
", recvBuf);



#ifdef _WIN32
    /* 关闭socket */
    closesocket(client_fd);
#else
    /* 关闭socket */
    close(client_fd);
#endif // _WIN32


    printf("client ended successfully
");
    exit(EXIT_SUCCESS);
}