目录
1 UNIX 域流式套接字
2 UNIX 域数据报套接字
1 UNIX 域流式套接字
UNIX 域流式套接字(UNIX domain stream socket)是一种在同一台主机上的进程之间进行通信的机制。它不依赖于网络协议栈,而是使用文件系统作为通信的基础。
UNIX 域流式套接字提供可靠的、双向的、面向连接的通信方式。与传统的套接字不同,UNIX 域套接字不需要经过网络协议栈,数据直接通过内核中的缓冲区进行传递,因此具有低延迟和高效率的特点。
UNIX 域流式套接字广泛用于本地进程之间的通信,例如在同一台服务器上的多个进程之间共享数据、同步操作等。它是一种高效、可靠的 IPC(进程间通信)机制。
本地地址
struct sockaddr_un {unsigned short sun_family; /* 协议类型 */char sun_path[108]; /* 套接字文件路径 */
};
UNIX 域流式套接字的用法和 TCP 套接字基本一致,区别在于使用的协议和地址不同
UNIX 域流式套接字服务器端流程如下:
(1)创建 UNIX 域流式套接字。
(2)绑定本地地址(套接字文件)。
(3)设置监听模式。
(4)接收客户端的连接请求。
(5)发送/接收数据。
补充:在linux中输入man bind,下方有流套接字示例代码
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>#define MY_SOCK_PATH "/tmp/my_sock_file"
#define LISTEN_BACKLOG 50#define handle_error(msg) \do { perror(msg); exit(EXIT_FAILURE); } while (0)int main(int argc, char *argv[])
{int sfd, cfd;struct sockaddr_un my_addr, peer_addr;socklen_t peer_addr_size;char buf[BUFSIZ] = {};sfd = socket(AF_UNIX, SOCK_STREAM, 0);if (sfd == -1)handle_error("socket");memset(&my_addr, 0, sizeof(struct sockaddr_un));my_addr.sun_family = AF_UNIX;strncpy(my_addr.sun_path, MY_SOCK_PATH,sizeof(my_addr.sun_path) - 1);if (bind(sfd, (struct sockaddr *) &my_addr,sizeof(struct sockaddr_un)) == -1)handle_error("bind");if (listen(sfd, LISTEN_BACKLOG) == -1)handle_error("listen");peer_addr_size = sizeof(struct sockaddr_un);cfd = accept(sfd, (struct sockaddr *) &peer_addr,&peer_addr_size);if (cfd == -1)handle_error("accept");recv(cfd, buf, BUFSIZ, 0);printf("%s\n", buf);close(cfd);close(sfd);//不删除文件,下次打开会出错remove(MY_SOCK_PATH);return 0;
}
UNIX 域流式套接字客户端流程如下。
(1)创建 UNIX 域流式套接字。
(2)指定服务器端地址(套接字文件)。
(3)建立连接。
(4)发送/接收数据。
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>#define MY_SOCK_PATH "/tmp/my_sock_file"#define handle_error(msg) \do { perror(msg); exit(EXIT_FAILURE); } while (0)int main(int argc, char *argv[])
{int fd;struct sockaddr_un peer_addr;char buf[BUFSIZ] = {"Hello World!"};fd = socket(AF_UNIX, SOCK_STREAM, 0);if (fd == -1)handle_error("socket");memset(&peer_addr, 0, sizeof(struct sockaddr_un));peer_addr.sun_family = AF_UNIX;strncpy(peer_addr.sun_path, MY_SOCK_PATH,sizeof(peer_addr.sun_path) - 1);if (connect(fd, (struct sockaddr *) &peer_addr,sizeof(struct sockaddr_un)) == -1)handle_error("connect");printf("%s\n",buf);send(fd, buf, strlen(buf), 0);close(fd);return 0;
}
2 UNIX 域数据报套接字
UNIX 域数据套接字(UNIX domain datagram socket)是一种在同一台主机上的进程之间进行通信的机制。类似于UNIX 域流式套接字,UNIX 域数据套接字也不依赖于网络协议栈,而是使用文件系统作为通信的基础。
UNIX 域数据套接字提供无连接的、不可靠的通信方式。它使用数据报(datagram)进行通信,每个数据报都是独立的、自包含的消息单元。与UNIX 域流式套接字不同,UNIX 域数据套接字不需要建立连接,数据可以直接发送和接收。
UNIX 域数据套接字适用于面向消息的通信模式,可以用于实现进程间的异步通信,发送和接收各种类型的消息,如命令、状态信息等。它也常用于本地进程间的通信,特别是在需要高效、低延迟的情况下。与UNIX 域流式套接字相比,UNIX 域数据套接字在功能上更为简单,但传输效率更高。
UNIX 域用户数据报套接字的流程可参考 UDP 套接字
UNIX 域流式套接字服务器端流程如下:
(1)创建 UNIX 域流式套接字。
(2)绑定本地地址(套接字文件)。
(3)发送/接收数据。
服务端
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>#define MY_SOCK_PATH "/tmp/my_sock_file"
#define handle_error(msg) \do { perror(msg); exit(EXIT_FAILURE); } while (0)int main(int argc, char *argv[])
{int fd;struct sockaddr_un my_addr, peer_addr;socklen_t peer_addr_size;char buf[BUFSIZ] = {};fd = socket(AF_UNIX, SOCK_DGRAM, 0);if (fd == -1)handle_error("socket");memset(&my_addr, 0, sizeof(struct sockaddr_un));my_addr.sun_family = AF_UNIX;strncpy(my_addr.sun_path, MY_SOCK_PATH,sizeof(my_addr.sun_path) - 1);if (bind(fd, (struct sockaddr *) &my_addr,sizeof(struct sockaddr_un)) == -1)handle_error("bind");peer_addr_size = sizeof(struct sockaddr_un);recvfrom(fd, buf, BUFSIZ, 0, (struct sockaddr *) &peer_addr,&peer_addr_size);printf("%s\n",buf);close(fd);//不删除文件下次打开会出错remove(MY_SOCK_PATH);return 0;
}
客户端
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>#define MY_SOCK_PATH "/tmp/my_sock_file"
#define handle_error(msg) \do { perror(msg); exit(EXIT_FAILURE); } while (0)int main(int argc, char *argv[])
{int fd;struct sockaddr_un peer_addr;socklen_t peer_addr_size;char buf[BUFSIZ] = {"Hello World!"};fd = socket(AF_UNIX, SOCK_DGRAM, 0);if (fd == -1)handle_error("socket");memset(&peer_addr, 0, sizeof(struct sockaddr_un));peer_addr.sun_family = AF_UNIX;strncpy(peer_addr.sun_path, MY_SOCK_PATH,sizeof(peer_addr.sun_path) - 1);peer_addr_size = sizeof(struct sockaddr_un);printf("%s\n", buf);sendto(fd, buf, strlen(buf), 0, (struct sockaddr *) &peer_addr,peer_addr_size);close(fd);//不删除文件下次打开会出错remove(MY_SOCK_PATH);return 0;
}