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

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

一: 简介

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

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

Windows 已于 Windows 10 17063 开始支持UDS。
由于 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\n", ret);
    }
    ~SocketInit() {
        printf("~SocketInit\n");
        WSACleanup();
    }
};
const SocketInit sInit;
#endif // _WIN32

// 创建临时 sock 文件
/*
win: C:\Users\ADMINI~1\AppData\Local\Temp\jimbo_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\n", s_sock_path.c_str());

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

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

    printf("\nthis is server!\n\n");
    
    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!\n");

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

    printf("listen succeed!\n");

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

    char buf[1024];
    if (recv(client_fd, buf, 1024, 0) < 0) {
        perror("socket recv failed");
        exit(EXIT_FAILURE);
    }
    printf("server recv response: [%s]\n", 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!\n");

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


    printf("server ended successfully\n");
    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\n", ret);
    }
    ~SocketInit() {
        printf("~SocketInit\n");
        WSACleanup();
    }
};
const SocketInit sInit;
#endif // _WIN32

// 创建临时 sock 文件
/*
win: C:\Users\ADMINI~1\AppData\Local\Temp\jimbo_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\n", s_sock_path.c_str());
}


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

    printf("\nthis is client!\n\n");
    
    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!\n");

    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!\n");

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



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


    printf("client ended successfully\n");
    exit(EXIT_SUCCESS);
}
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值