UNIX域套接字

UNIX 域套接字类型

  • UNIX 域流式套接字
    • 类似于 TCP,提供面向连接、可靠的双向通信
    • 使用本地文件路径作为地址,适用于本地进程间通信
  • UNIX 域数据报套接字
    • 类似于 UDP,提供无连接、不可靠的通信
    • 同样使用本地文件路径作为地址

本地地址结构

c 复制代码
struct sockaddr_un {
    unsigned short sun_family;  // 协议类型,如 AF_UNIX
    char sun_path[108];         // 套接字文件路径
};

UNIX 域流式套接字

  • 用法和 TCP 套接字基本一致,区别在于使用的协议和地址不同

服务端流程

  • 创建 UNIX 域流式套接字
  • 绑定本地地址(套接字文件)
  • 设置监听模式
  • 接收客户端的连接请求
  • 发送/接收数据

示例代码

c 复制代码
#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 域流式套接字
  • 指定服务器端地址(套接字文件)
  • 建立连接
  • 发送/接收数据

示例代码

c 复制代码
#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;
}

UNIX 域数据报套接字

  • 流程类似于 UDP 套接字,无需建立连接
  • UNIX 域流式套接字服务器端流程如下:
    • 创建 UNIX 域流式套接字
    • 绑定本地地址(套接字文件)
    • 发送/接收数据

示例代码

服务端

c 复制代码
#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;
}

客户端

c 复制代码
#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;
}
相关推荐
郝学胜-神的一滴6 小时前
epoll 反应堆模型深度拆解:从红黑树到回调闭环,手写高性能回射服务器
linux·运维·服务器·开发语言·c++·unix
♛识尔如昼♛1 天前
C 进阶(1) - Unix 基础
unix
ZenosDoron1 天前
Linux/Unix 系统中用于创建链接的命令ln
linux·运维·unix
郝学胜-神的一滴2 天前
深入epoll封装:event_set与event_add核心原理剖析
linux·服务器·开发语言·网络·c++·unix
郝学胜-神的一滴4 天前
从底层看透Linux高性能服务器:epoll自定义封装与超时清理实战
linux·服务器·c++·网络协议·tcp/ip·unix
IMPYLH5 天前
Linux 的 split 命令
linux·运维·python·bash·运维开发·unix
郝学胜-神的一滴5 天前
深入epoll反应堆模型:从libevent源码看高性能IO设计精髓
linux·服务器·开发语言·c++·网络协议·unix·信息与通信
郝学胜-神的一滴6 天前
epoll 边缘触发 vs 水平触发:从管道到套接字的深度实战
linux·服务器·开发语言·c++·网络协议·unix
森叶8 天前
告别端口占用!用 Unix Domain Socket 管道让 Express 飞起来
服务器·unix·express
CS创新实验室9 天前
CS实验室行业报告:自动驾驶领域就业分析报告
人工智能·自动驾驶·unix