Unix域套接字主要用于本机进程间的通信,传输速度是TCP的两倍。

1 Unix域地址结构

  1. #define UNIX_PATH_MAX 108
  2. struct sockaddr_un{
  3. sa_family_t sun_family; //AF_UNIX或AF_LOCAL
  4. char sun_path[UNIX_PATH_MAX]; //pathname, unix域用路径名表示地址
  5. };

2 Unix域套接字注意

  • sun_path最好使用绝对路径
  • unix域协议支持流式和数据报式套接口
  • unix域协议connect发现监听队列满里,会立刻返回ECONNREFUSED, 和TCP不同。

3 代码示例

server

  1. #include <unistd.h>
  2. #include <sys/un.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <string.h>
  10. #define ERR_EXIT(m)\
  11. do\
  12. {\
  13. perror(m);\
  14. exit(EXIT_FAILURE);\
  15. }while(0)
  16. void handle_subprocess(int conn)
  17. {
  18. char buf[1024];
  19. int ret;
  20. while(1)
  21. {
  22. memset(buf, 0, sizeof(buf));
  23. ret = read(conn, buf, sizeof(buf));
  24. if (ret == -1)
  25. {
  26. if (ret == EINTR)
  27. continue;
  28. ERR_EXIT("read failed");
  29. }
  30. if (ret == 0)
  31. {
  32. printf("client closed\r\n");
  33. break;
  34. }
  35. printf("%s\r\n", buf);
  36. write(conn, buf, strlen(buf));
  37. }
  38. close(conn);
  39. }
  40. int main()
  41. {
  42. int sock;
  43. //仍然使用socket函数创建socket,协议族指定为PF_UNIX
  44. if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
  45. ERR_EXIT("create unix socket failed");
  46. unlink("test socket");//先删除之前留下的socket文件
  47. sockaddr_un servaddr;
  48. servaddr.sun_family = AF_UNIX; //这里指定unix域协议
  49. strcpy(servaddr.sun_path, "test socket"); //指定socket文件,会再目录下生成该名称的文件
  50. //bind
  51. if (bind(sock, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)
  52. ERR_EXIT("bind failed");
  53. //listen
  54. if (listen(sock, SOMAXCONN) < 0)
  55. ERR_EXIT("listen failed");
  56. int conn;
  57. pid_t pid;
  58. while(1)
  59. {
  60. conn = accept(sock, NULL, NULL);
  61. if (conn == -1)
  62. {
  63. if (conn == EINTR)
  64. continue;
  65. ERR_EXIT("accept failed");
  66. }
  67. pid = fork();
  68. if (pid == -1)
  69. ERR_EXIT("fork failed");
  70. if (pid == 0)//子进程
  71. {
  72. close(sock);
  73. handle_subprocess(conn);
  74. exit(EXIT_SUCCESS);
  75. }
  76. else
  77. {
  78. close(conn);
  79. }
  80. }
  81. close(sock);
  82. return 0;
  83. }

client

  1. #include <unistd.h>
  2. #include <sys/un.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <string.h>
  10. #define ERR_EXIT(m)\
  11. do\
  12. {\
  13. perror(m);\
  14. exit(EXIT_FAILURE);\
  15. }while(0)
  16. int main()
  17. {
  18. int sock;
  19. if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
  20. ERR_EXIT("create unix socket failed");
  21. sockaddr_un servaddr;
  22. servaddr.sun_family = AF_UNIX; //这里指定unix域协议
  23. strcpy(servaddr.sun_path, "test socket");
  24. //start connect to the server
  25. if (connect(sock, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)
  26. ERR_EXIT("connect failed");
  27. char buf[1024];
  28. while (fgets(buf, sizeof(buf), stdin) != NULL)
  29. {
  30. write(sock, buf, strlen(buf));
  31. read(sock, buf, sizeof(buf));//read reply from server
  32. printf("received from server: %s\r\n", buf);
  33. memset(buf, 0, sizeof(buf));
  34. }
  35. close(sock);
  36. }

4 socketpair全双工流通道

头文件: <sys/socket.h>
函数定义: int socketpair(int domain, int type, int protocol, int sv[2]);
功能: 创建一个全双工的流管道,用于父子进程间通信; 返回值为0,失败返回-1
参数:

  • domain: 协议家族,指定为PF_UNIX
  • type: 套接字类型,SOCK_STREAM流式套接字
  • protocol: 协议类型
  • sv: 返回的套接字对

socketpair不同与普通的pipe,是全双工的,两端可以同时发送和接收数据。代码示例如下:

  1. #include "common.h"
  2. int main()
  3. {
  4. int socks[2];
  5. if(socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)
  6. ERR_EXIT("socketpair failed");
  7. pid_t pid;
  8. pid = fork();
  9. if (pid > 0)
  10. {
  11. //父进程
  12. int val = 0;
  13. close(socks[1]);//只需要保留一个socket在该进程,另一个在另一进程
  14. while(1)
  15. {
  16. ++val;
  17. printf("send data: %d\r\n", val);
  18. write(socks[0], &val, sizeof(val));
  19. read(socks[0], &val, sizeof(val));
  20. printf("receive data: %d\r\n", val);
  21. sleep(1);
  22. }
  23. }
  24. else if (pid == 0)
  25. {
  26. int val;
  27. close(socks[0]);
  28. while(1)
  29. {
  30. read(socks[1], &val, sizeof(val));
  31. ++val;
  32. write(socks[1], &val, sizeof(val));
  33. }
  34. }
  35. return 0;
  36. }