• 进程间通信(IPC)的方法:UNIX域套接字


          UNIX域套接字(UNIX domain socket)为我们提供了一种在进程之间建立通信通道的便捷方法,具有许多有用的内置功能。它支持面向流(TCP)和面向数据报(UDP)协议作为TCP/IP互联网套接字。我们还可以在阻塞和非阻塞模式之间进行选择。
          首先需要创建套接字并在套接字函数中指定AF_UNIX作为域套接字。创建套接字后,必须使用绑定函数将套接字绑定到唯一的文件路径。与AF_INET域中的Internet套接字绑定到唯一的IP地址和端口号不同,UNIX域套接字绑定到文件路径。文件系统中创建的此文件,当程序关闭且不再需要该文件时,你必须手动将其删除。
          UNIX域套接字与server/client网络套接字通信没有太大不同,但它旨在供本地文件系统使用。server/client网络套接字介绍参考:https://blog.csdn.net/fengbingchun/article/details/107848160

          UNIX域套接字总结
          (1).同步;
          (2).极高的吞吐量;存储设备速度限制;
          (3).双向通信;
          (4).以线性方式读写;
          (5).自动内存管理。

          注:以上内容主要来自网络整理。

          测试代码如下:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main()
    10. {
    11. // reference: https://biendltb.github.io/tech/inter-process-communication-ipc-in-cpp/
    12. const char* server_sock_path = "/tmp/unix_sock.server";
    13. const char* client_sock_path = "/tmp/unix_sock.client";
    14. pid_t pid = fork(); // create two processes of client and server
    15. if (pid < 0) {
    16. fprintf(stderr, "fail to fork\n");
    17. return -1;
    18. }
    19. if (pid != 0) { // server process(parent process)
    20. auto server_sock = socket(AF_UNIX, SOCK_STREAM, 0); // open the server socket with the SOCK_STREAM type
    21. if (server_sock == -1) {
    22. fprintf(stderr, "SERVER: fail to socket: %s\n", strerror(errno));
    23. exit(1);
    24. }
    25. // bind to an address on file system
    26. // similar to other IPC methods, domain socket needs to bind to a file system, so that client know the address of the server to connect to
    27. struct sockaddr_un server_addr;
    28. memset(&server_addr, 0, sizeof(server_addr));
    29. server_addr.sun_family = AF_UNIX;
    30. strcpy(server_addr.sun_path, server_sock_path);
    31. unlink(server_sock_path); // unlink the file before bind, unless it can't bind: error info: Address already in use
    32. auto rc = bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
    33. if (rc == -1) {
    34. fprintf(stderr, "SERVER: fail to bind: %s\n", strerror(errno));
    35. exit(1);
    36. }
    37. // listen and accept client connection
    38. // set the server in the "listen" mode and maximum pending connected clients in queue
    39. rc = listen(server_sock, 10);
    40. if (rc == -1) {
    41. fprintf(stderr, "SERVER: fail to listen: %s\n", strerror(errno));
    42. exit(1);
    43. }
    44. fprintf(stdout, "SERVER: Socket listening...\n");
    45. struct sockaddr_un client_addr;
    46. auto len = sizeof(client_addr);
    47. int client_fd = accept(server_sock, (struct sockaddr *)&client_addr, (socklen_t*)&len);
    48. if (client_fd == -1) {
    49. fprintf(stderr, "SERVER: fail to accept: %s\n", strerror(errno));
    50. exit(1);
    51. }
    52. fprintf(stdout, "SERVER: Connected to client at: %s\n", client_addr.sun_path);
    53. fprintf(stdout, "SERVER: Wating for message...\n");
    54. const int buf_len = 256;
    55. char buf[buf_len];
    56. memset(buf, 0, buf_len);
    57. int byte_recv = recv(client_fd, buf, buf_len, 0);
    58. if (byte_recv == -1) {
    59. fprintf(stderr, "SERVER: fail to recv: %s\n", strerror(errno));
    60. exit(1);
    61. }
    62. else
    63. fprintf(stdout, "SERVER: Server received message: %s.\n", buf);
    64. fprintf(stdout, "SERVER: Respond to the client...\n");
    65. memset(buf, 0, buf_len);
    66. strcpy(buf, "hello from server");
    67. rc = send(client_fd, buf, buf_len, 0);
    68. if (rc == -1) {
    69. fprintf(stderr, "SERVER: fail to send:%s\n", strerror(errno));
    70. exit(1);
    71. }
    72. fprintf(stdout, "SERVER: Done!\n");
    73. close(server_sock);
    74. close(client_fd);
    75. remove(server_sock_path); // remove access to a file named
    76. int status;
    77. auto pid2 = wait(&status); // system call suspends execution of the calling thread until one of its children terminates
    78. fprintf(stdout, "process ID of the terminated child: %d\n", pid2);
    79. if (WIFEXITED(status)) { // returns true if the child terminated normally
    80. fprintf(stdout, "child process ended with: exit(%d)\n", WEXITSTATUS(status));
    81. }
    82. if (WIFSIGNALED(status)) { // returns true if the child process was terminated by a signal
    83. fprintf(stderr, "child process ended with: kill -%d\n", WTERMSIG(status));
    84. }
    85. }
    86. if (pid == 0) { // client process(child process)
    87. int client_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    88. if (client_sock == -1) {
    89. fprintf(stderr, "CLIENT: fail to socket: %s\n", strerror(errno));
    90. exit(1);
    91. }
    92. // bind client to an address on file system
    93. // Note: this binding could be skip if we want only send data to server without receiving
    94. struct sockaddr_un client_addr;
    95. memset(&client_addr, 0, sizeof(client_addr));
    96. client_addr.sun_family = AF_UNIX;
    97. strcpy(client_addr.sun_path, client_sock_path);
    98. unlink (client_sock_path);
    99. auto rc = bind(client_sock, (struct sockaddr *)&client_addr, sizeof(client_addr));
    100. if (rc == -1) {
    101. fprintf(stderr, "CLIENT: fail to bind: %s\n", strerror(errno));
    102. exit(1);
    103. }
    104. // Set server address and connect to it
    105. struct sockaddr_un server_addr;
    106. server_addr.sun_family = AF_UNIX;
    107. strcpy(server_addr.sun_path, server_sock_path);
    108. rc = connect(client_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    109. if (rc == -1) {
    110. fprintf(stderr, "CLIENT: fail to connect: %s\n", strerror(errno));
    111. exit(1);
    112. }
    113. fprintf(stdout, "CLIENT: Connected to server.\n");
    114. // Send message to server
    115. const int buf_len = 256;
    116. char buf[buf_len];
    117. memset(buf, 0, buf_len);
    118. strcpy(buf, "hello from client");
    119. rc = send(client_sock, buf, buf_len, 0);
    120. if (rc == -1) {
    121. fprintf(stderr, "CLIENT: fail to send: %s\n", strerror(errno));
    122. exit(1);
    123. }
    124. fprintf(stdout, "CLIENT: Sent a message to server.\n");
    125. fprintf(stdout, "CLIENT: Wait for respond from server...\n");
    126. memset(buf, 0, buf_len);
    127. rc = recv(client_sock, buf, buf_len, 0);
    128. if (rc == -1) {
    129. fprintf(stderr, "CLIENT: fail to recv: %s\n", strerror(errno));
    130. exit(1);
    131. }
    132. else
    133. fprintf(stdout, "CLIENT: Message received: %s\n", buf);
    134. fprintf(stdout, "CLIENT: Done!\n");
    135. close(client_sock);
    136. remove(client_sock_path);
    137. exit(0);
    138. }
    139. fprintf(stdout, "====== test finish ======\n");
    140. return 0;
    141. }

          编译脚本build.sh如下:

    1. #! /bin/bash
    2. if [ -d build ]; then
    3. echo "build directory already exists, it does not need to be created again"
    4. else
    5. mkdir -p build
    6. fi
    7. cd build
    8. cmake ..
    9. make
    10. rc=$?
    11. if [[ ${rc} != 0 ]];then
    12. echo "#### ERROR: please check ####"
    13. exit ${rc}
    14. fi
    15. echo "==== build finish ===="

          CMakeLists.txt内容如下:

    1. cmake_minimum_required(VERSION 3.22)
    2. project(samples_multi_process)
    3. set(CMAKE_BUILD_TYPE Release) # only works under linux
    4. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2 -std=c++17")
    5. file(GLOB samples ${PROJECT_SOURCE_DIR}/test_*.cpp)
    6. #message(STATUS "samples: ${samples}")
    7. foreach(sample ${samples})
    8. string(REGEX MATCH "[^/]+$" name ${sample})
    9. string(REPLACE ".cpp" "" exec_name ${name})
    10. #message(STATUS "exec name: ${exec_name}")
    11. add_executable(${exec_name} ${sample})
    12. target_link_libraries(${exec_name} rt)
    13. endforeach()

          执行结果如下所示:

          GitHubhttps://github.com/fengbingchun/Linux_Code_Test

  • 相关阅读:
    AlphaTensor论文阅读分析-矩阵乘法优化-强化学习
    SSH 多密钥配置
    Bio初级通讯案例
    Cube.js 试试这个新的数据分析开源工具
    浏览器表单的基本使用
    .NET餐厅管理系统菜品添加页面后端
    基于nodejs的在线跑腿系统-计算机毕业设计
    2310D库功能还是语言功能
    P1396 营救-最短路dijkstra和最小生成树kruskal+并查集
    【LeetCode-中等题】210. 课程表 II
  • 原文地址:https://blog.csdn.net/fengbingchun/article/details/132940354