UNIX 域协议

ops/2024/10/11 1:17:57/

1. UNIX域协议

利用socket 编程接口实现本地进程间通信

UNIX域协议套接字:可以使用TCP,也可以使用UDP

        SOCK_STREAM -----> TCP   面向字节流

        SOCK_DGRAM   -----> UDP  面向数据报


        UNIX域协议并不是一个实际的协议族,而是在单个主机上执行客户 / 服务器 通信的一种方式 (IPC的一种方法)

        UNIX域数据报 (SOCK_DGRAM)是可靠的,不会丢失消息

        IP协议中使用
IP地址 + 端口号标识客户端和服务端

        UNIX域协议使用普通文件系统中的路径名 (绝对路径) 标识客户端和服务端

如果这个路径不存在则创建后标识其为 客户/服务器 的地址
如果这个路径已经存在了则会报错:bind failed: Address already in use
所以在运行前先删掉,再去创建并且绑定unlink(绝对路径名);

UNIX域协议的特点:

        和TCP比较,速度快,数据报不要传递到主机外,也不需要进行封包和拆包

        UNIX域协议使用一个绝对路径作为“IP”地址

#include <sys/un.h>

//vim /usr/include/linux/un.h
#define UNIX_PATH_MAX 108// Unix域协议的地址结构体的具体描述
// #include <sys/un.h>
struct sockaddr_un {__kernel_sa_family_t sun_family; // 协议族char sun_path[UNIX_PATH_MAX];/* Unix域协议地址,是以'\0'结束的本地文件系统中的绝对路径名,如: "/tmp/xxx.socket"*/
}

编程方法:TCP / UDP

问题:客户端成功发送数据出去,服务端成功接收到数据,但是并没有成功将客户端的地址打印出来?

        客户端没有绑定地址。如果说服务端要向客户端发送数据的话,没有“IP”地址就没办法定位对方的具体位置了,所以要实现能获取客户端地址,则客户端需要绑定地址。

        使用UDP实现UNIX域协议如果客户端不绑定,服务器就不能发送信息给客户端

2. 代码实现

2.1 基于TCP实现UNIX域协议

unix_tcp_client.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>#define SERVICEPATHNAME "/home/china/s"
#define CLIENTPATHNAME "/home/china/c"int main(int argc, char *argv[]) {unlink(CLIENTPATHNAME);// (1) socket:创建一个套接字int sockfd =  socket(AF_UNIX, SOCK_STREAM, 0);if (sockfd == -1) {perror("unix socket failed");return -1;}// (2) bind// 需要一个网络地址结构体struct sockaddr_un cAddr;memset(&cAddr, 0, sizeof(cAddr));cAddr.sun_family = AF_UNIX; // 协议族strcpy(cAddr.sun_path, SLIENTPATHNAME);int res = bind(sockfd, (struct sockaddr *)&cAddr, sizeof(cAddr));if (res == -1) {perror("unix bind failed");close(sockfd);return -1;}printf("bind success\n");// (3) connectstruct sockaddr_un sAddr;memset(&sAddr, 0, sizeof(sAddr));sAddr.sun_family = AF_UNIX; // 协议族strcpy(sAddr.sun_path, SERVICEPATHNMAE);res = connect(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));if (res == -1) {perror("unix connect failed");return -1;}printf("unix connect succeed\n");while (1) {// (3) 进行通信,读写数据char buf[250] = {0};scanf("%s", buf);int w = send(sockfd, buf, strlen(buf), 0);printf("w = %d\n", w);if (buf[0] == '#') {break;}char buff[250] = {0};int r = recv(sockfd, buff, 250, 0);printf("r = %d,message = %s\n", r, buff);}// (4) 关闭socket套接字close(sockfd);return 0;
} 

unix_tcp_server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>#define SERVICEPATHNAME "/home/china/s"int main(int argc, char *argv[]) {unlink(SERVICEPATHNMAE);// (1) socket:创建一个套接字int sockfd =  socket(AF_UNIX, SOCK_STREAM, 0);if (sockfd == -1) {perror("unix socket failed");return -1;}// (2) bind:把一个套接字和网络地址绑定到一起// 需要一个网络地址结构体struct sockaddr_un sAddr;memset(&sAddr, 0, sizeof(sAddr));sAddr.sun_family = AF_UNIX; // 协议族strcpy(sAddr.sun_path, SERVICEPATHNAME);int res = bind(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));if (res == -1) {perror("unix bind failed");close(sockfd);return -1;}printf("bind success\n");// (3) listen:让套接字进入“监听模式”res = listen(sockfd, 5);if (res == -1) {perror("unix listen failed");close(sockfd);return -1;}// 保存客户端的网络地址struct sockaddr_un cAddr;// 保存客户端的网络地址的长度socklen_t addrlen = sizeof(cAddr);// (4) 当没有客户端请求的时候,accept是阻塞的int confd = accept(sockfd, (struct sockaddr *)&cAddr, &addrlen);if (confd == -1) {close(sockfd);return -1;}printf("accept success\n");printf("client path:%s\n", cAddr.sun_path);while (1) {// (5) 进行通信,读写数据char buf[250] = {0};int r = recv(confd, buf, 250, 0);if (r != -1) {printf("r = %d,messagee = %s\n", r, buf);}if (buf[0] == '#') {close(confd);break;}send(confd, "hello", sizeof("hello"), 0);}// (6) 关闭socket套接字:"四次挥手"close(sockfd);return 0;
}
2.2 基于UDP实现UNIX域协议

unix_udp_client.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>#define SERVICEPATHNAME "/home/china/s"
#define CLIENTPATHNAME "/home/china/c"int main(int argc, char *argv[]) {unlink(CLIENTPATHNAME);// 1. socketint sockfd =  socket(AF_UNIX, SOCK_DGRAM, 0);if (sockfd == -1) {perror("udp socket failed");return -1;}// 2. 必须bind// 需要一个网络地址结构体struct sockaddr_un cAddr;memset(&cAddr, 0, sizeof(cAddr));cAddr.sun_family = AF_UNIX; // 协议族strcpy(cAddr.sun_path, CLIENTPATHNAME);int res = bind(sockfd, (struct sockaddr *)&cAddr, sizeof(cAddr));if (res == -1) {perror("unix bind failed");close(sockfd);return -1;}// 需要一个网络地址,指定发给哪一个服务器struct sockaddr_un sAddr;memset(&sAddr, 0, sizeof(sAddr));sAddr.sun_family = AF_UNIX; // 协议族strcpy(sAddr.sun_path, SERVICEPATHNAME);// 当服务器发信息给我时,保存该服务器的网络地址struct sockaddr_un server_addr;socklen_t addrlen = sizeof(server_addr);while (1) {// 2. sendtochar buf[250] = {0};scanf("%s", buf);int w =  sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&sAddr, sizeof(sAddr));printf("w = %d\n", w);if (buf[0] == '#') { // 退出条件break;}// 3. recvfromchar buff[250] = {0};int r = recvfrom(sockfd, buff, 250, 0, (struct sockaddr*)&server_addr, &addrlen);if (r > 0) {printf("r = %d, buff = %s\n", r, buff);printf("server path:%s\n", server_addr.sun_path);}}// 4. closeclose(sockfd);return 0;
}

unix_udp_server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>#define SERVICEPATHNMAE "/home/china/s"int main(int argc, char *argv[]) {unlink(SERVICEPATHNMAE);// 1. socketint sockfd =  socket(AF_UNIX, SOCK_DGRAM, 0);if (sockfd == -1) {perror("unix socket failed");return -1;}// 2. bind// 需要一个网络地址结构体struct sockaddr_un sAddr;memset(&sAddr, 0, sizeof(sAddr));sAddr.sun_family = AF_UNIX; // 协议族strcpy(sAddr.sun_path, SERVICEPATHNMAE);int res = bind(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));if (res == -1) {perror("unix bind failed");close(sockfd);return -1;}// 保存客户端的网络地址struct sockaddr_un cAddr;// 保存客户端的网络地址的长度socklen_t addrlen = sizeof(cAddr);while (1) {// 3. recvfromchar buf[250] = {0};int r = recvfrom(sockfd, buf, 250, 0, (struct sockaddr *)&cAddr, &addrlen);if (r > 0) {printf("r = %d, buf = %s\n", r, buf);printf("client path:%s\n", cAddr.sun_path);}// 4. sendtochar buff[250] = {0};scanf("%s", buff);int w = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&cAddr, addrlen);printf("w = %d\n", w);}// 5. closeclose(sockfd);return 0;
}

http://www.ppmy.cn/ops/86982.html

相关文章

第13周 简历职位功能开发与Zookeeper实战

第13周 简历职位功能开发与Zookeeper实战 本章概述1. Mysql8窗口函数over使用1.1 演示表结构与数据1.2 案例1:获取男女总分数1.3 案例2****************************************************************************************本章概述 1. Mysql8窗口函数over使用 参考案例…

Nginx实现数据库端口转发

作者&#xff1a;红米 一、需求 客户想要将IDC服务器的数据库端口暴漏在公网上&#xff0c;然后其他业务来调数据库接口。为了保证安全&#xff0c;只开放指定的公网ip访问。 二、逻辑设计 由于客户的IDC服务器与云ECS服务器通过专线打通&#xff0c;所以只需要在云ECS服务…

每天一个数据分析题(四百五十七)- 分层随机抽样

一项针对全国25-35岁用户群的手机喜好调查&#xff0c;但调研项目经费大概是10万元&#xff0c;并且用户群相对集中在中国中部城市。前期预调研显示&#xff0c;用户群的方差和调研费用不等。以下哪种情况是比较适宜的调查方式&#xff1f; A. 简单随机抽样&#xff08;全国抽…

【Linux】多路转接 -- select函数

文章目录 1. 认识select函数2. select函数原型3. socket就绪条件4. select工作流程5. select服务器6. select的优缺点 首先我们要了解一下&#xff0c;什么是多路转接&#xff1f; 多路转接也叫多路复用&#xff0c;是一种用于管理多个IO通道的技术。它能实现同时监听和处理多个…

NC 缺失的第一个正整数

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 给定一个无重…

C++ - 负载均衡式在线OJ

目录 一.项目的宏观结构 1.1 只实现类似 leetcode 的题⽬列表在线编程功能 1.2 项⽬宏观结构 1.3编写思路 二.所⽤技术与开发环境 2.1 所用技术 2.2 开发环境 三.compiler 服务设计 3.1 编译功能 3.2 日志功能 3.3 运⾏功能 3.4 编译并运⾏功能 3.5 把编译并运⾏功…

教程系列4 | 趋动云『社区项目』极速体验 LivePortrait 人脸表情“移花接木”大法

LivePortrait LivePortrait 由快手可灵大模型团队开源&#xff0c;只需 1 张原图就能生成动态视频。 LivePortrait 的核心优势在于其卓越的表情"迁移"技术&#xff0c;能够令静态图像中的人物瞬间焕发活力&#xff0c;无论是眨眼、微笑还是转头&#xff0c;皆栩栩如…

浅学爬虫-python爬虫基础

介绍与应用 Python爬虫是指利用Python编写程序从互联网上自动获取信息的技术。爬虫广泛应用于数据收集、价格监控、内容聚合、市场分析等领域。其基本原理是模拟浏览器发送HTTP请求获取网页数据&#xff0c;并通过解析HTML来提取所需的信息。 基本工具 Python中有许多强大的…