Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。提供 UDP 和 TCP 两种通信机制。 因为一些原因,项目现有软件架
Unix domain socket 或者 IPC socket是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。提供 UDP 和 TCP 两种通信机制。
因为一些原因,项目现有软件架构采用的都是 IPC sockte
中的 TCP
通信机制,虽然保证了通信的可靠性,但近期需要对该程序进行热迁移(基于 criu
),有连接的 IPC 套接字状态很难被保存和恢复,而 无连接的 UDP 只需要保证服务端先冻结、先恢复即可实现程序整体状态迁移,因此写下本文,记录迁移过程,最后提供示例程序,可以自行通过 BCompare
等文本对比工具对比差异。
模式差异
至于两种通信机制的差异,除了在创建套接字时声明的差异,具体的通信流程也有差异,在这里找到 CSDN @frank909 的两张图片,感觉很有代表性,在这里引用一下。
首先是 TCP的:
![https://cdn-imagehost.frytea.com/images/2021/01/13/202101131815253d04d69f377dae01.png](https://cdn-imagehost.frytea.com/images/2021/01/13/202101131815253d04d69f377dae01.png)
![https://cdn-imagehost.frytea.com/images/2021/01/13/202101131815253d04d69f377dae01.png](https://cdn-imagehost.frytea.com/images/2021/01/13/202101131815253d04d69f377dae01.png)
接下来是 UDP 的:
![https://cdn-imagehost.frytea.com/images/2021/01/13/2021011318145069f28463e2e1709c.png](https://cdn-imagehost.frytea.com/images/2021/01/13/2021011318145069f28463e2e1709c.png)
二者的差异,主要是这几点:
(1)TCP连接在 bind()
之后需要 listen()
,而UDP不需要。
(2)TCP连接在 bind()
和 listen()
后还需要 accept()
,用来得到客户端连接描述符,而UDP不需要。
(3)收发数据,TCP使用 recv()
, send()
, 而 UDP 使用 recvfrom()
, sendto()
。
(4)释放连接,TCP在客户端释放连接后需先释放 accept()
得到的客户端连接描述符,再 close(socket)
,而UDP直接 close(socket)
。
(1)TCP连接在bind()后需要 connect()
,而UDP不需要。
(2)收发数据,TCP使用 recv()
, send()
, 而 UDP 使用 recvfrom()
, sendto()
。
具体的差异可以查看下方的示例程序。
参考程序
TCP-Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <memory.h> #include <unistd.h> #include <stdio.h> #include <iostream>
using namespace std; const char* server_file = "/tmp/ipc_tcp_server.sock";
int main(int argc,char** argv) { int socket_fd = socket(AF_UNIX,SOCK_STREAM,0); if (socket_fd < 0) { perror("socket"); return -1; } struct sockaddr_un addr; memset(&addr,0,sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path,server_file); if (access(addr.sun_path,0) != -1) { remove(addr.sun_path); } if (bind(socket_fd,(sockaddr*)&addr,sizeof(addr)) < 0) { perror("bind"); return -1; } if (listen(socket_fd,12) < 0) { perror("listen"); return -1; } struct sockaddr_un clientaddr; socklen_t addrlen = sizeof(clientaddr); char msg_buf[1024]; int newcon = -1; newcon = accept(socket_fd,(sockaddr*)&clientaddr,&addrlen); if (newcon < 0) { perror("accept"); return -1; } while (1) { memset(msg_buf,'\0',1024); int rsize = recv(newcon,msg_buf,sizeof(msg_buf),0); if (rsize < 0) { perror("server recv error!"); break; } cout << "I'm Unix socket(TCP) server, recv a msg:" << msg_buf << " from: " << clientaddr.sun_path << endl; strcpy(msg_buf, "OK,I got it!"); int ssize = send(newcon, msg_buf, sizeof msg_buf, 0); if (ssize < 0) { perror("server send error!"); break; } sleep(1); } if (close(newcon) < 0) { perror("close accept"); return -1; } if (close(socket_fd) < 0) { perror("close socket"); return -1; } return 0; }
|
TCP-Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <memory.h> #include <unistd.h> #include <stdio.h> #include <iostream>
using namespace std;
const char* server_file = "/tmp/ipc_tcp_server.sock"; const char* client_file = "/tmp/ipc_tcp_client.sock";
int main(int argc,char** argv) { int socket_fd = socket(AF_UNIX,SOCK_STREAM,0); if (socket_fd < 0) { perror("client socket"); return -1; } struct sockaddr_un client_addr; memset(&client_addr,0,sizeof(client_addr)); client_addr.sun_family = AF_UNIX; strcpy(client_addr.sun_path,client_file);
if (access(client_addr.sun_path,0) != -1) { remove(client_addr.sun_path); }
if(bind(socket_fd,(sockaddr*)&client_addr,sizeof(client_addr)) < 0) { perror("client bind"); return -1; } struct sockaddr_un serveraddr; memset(&serveraddr,0,sizeof(serveraddr)); socklen_t addrlen = sizeof(serveraddr); serveraddr.sun_family = AF_UNIX; strcpy(serveraddr.sun_path,server_file); char msg_buf[1024]; int newcon = -1; newcon = connect(socket_fd,(sockaddr*)&serveraddr,addrlen); if (newcon < 0){ perror("client connect"); } while(1) { strcpy(msg_buf, "How are you !!!"); int ssize = send(socket_fd, msg_buf, sizeof msg_buf, 0); if (ssize < 0) { perror("client send"); continue; } int rsize = recv(socket_fd, msg_buf, sizeof(msg_buf), 0); if (rsize < 0) { perror("client recv"); continue; } cout << "I'm Unix socket(TCP) client,receive a msg :" << msg_buf << endl; sleep(1); } if (close(socket_fd) < 0) { perror("close"); return -1; } return 0; }
|
UDP-Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <memory.h> #include <unistd.h> #include <stdio.h> #include <iostream>
using namespace std; const char* server_file = "/tmp/ipc_udp_server.sock";
int main(int argc,char** argv) { int socket_fd = socket(AF_UNIX,SOCK_DGRAM,0); if (socket_fd < 0) { perror("socket"); return -1; } struct sockaddr_un addr; memset(&addr,0,sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path,server_file); if (access(addr.sun_path,0) != -1) { remove(addr.sun_path); } if (bind(socket_fd,(sockaddr*)&addr,sizeof(addr)) < 0) { perror("bind"); return -1; } struct sockaddr_un clientaddr; socklen_t addrlen = sizeof(clientaddr); char msg_buf[1024]; while (1) { memset(msg_buf,'\0',1024); int rsize = recvfrom(socket_fd,msg_buf,sizeof(msg_buf),0,(sockaddr*)&clientaddr,&addrlen); if (rsize < 0) { perror("server recv error!"); break; } cout << "I'm Unix socket(UDP) server, recv a msg: " << msg_buf << " from: " << clientaddr.sun_path << endl; strcpy(msg_buf, "OK,I got it!"); int ssize = sendto(socket_fd, msg_buf, sizeof msg_buf,0,(sockaddr*)&clientaddr,addrlen); if (ssize < 0) { perror("server send error!"); break; } sleep(1); } if (close(socket_fd) < 0) { perror("close socket"); return -1; } return 0; }
|
UDP-Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <memory.h> #include <unistd.h> #include <stdio.h> #include <iostream>
using namespace std;
const char* server_file = "/tmp/ipc_udp_server.sock"; const char* client_file = "/tmp/ipc_udp_client.sock";
int main(int argc,char** argv) { int socket_fd = socket(AF_UNIX,SOCK_DGRAM,0); if (socket_fd < 0) { perror("client socket"); return -1; } struct sockaddr_un client_addr; memset(&client_addr,0,sizeof(client_addr)); client_addr.sun_family = AF_UNIX; strcpy(client_addr.sun_path,client_file);
if (access(client_addr.sun_path,0) != -1) { remove(client_addr.sun_path); }
if(bind(socket_fd,(sockaddr*)&client_addr,sizeof(client_addr)) < 0) { perror("client bind"); return -1; } struct sockaddr_un serveraddr; memset(&serveraddr,0,sizeof(serveraddr)); socklen_t addrlen = sizeof(serveraddr); serveraddr.sun_family = AF_UNIX; strcpy(serveraddr.sun_path,server_file); char msg_buf[1024]; while(1) { strcpy(msg_buf, "How are you !!!"); int ssize = sendto(socket_fd, msg_buf, sizeof msg_buf, 0, (sockaddr*)&serveraddr,addrlen); if (ssize < 0) { perror("client sendto"); continue; } int rsize = recvfrom(socket_fd, msg_buf, sizeof(msg_buf), 0,(sockaddr*)&serveraddr, &addrlen); if (rsize < 0) { perror("client recv"); continue; } cout << "I'm Unix socket(TCP) client,receive a msg :" << msg_buf << endl; sleep(1); } if (close(socket_fd) < 0) { perror("close"); return -1; } return 0; }
|
源文件
ipc_test.zip
参考文献