macOS跨进程通信: Unix Domain Socket 创建实例

macOS跨进程通信: Unix Domain Socket 创建实例

一: 简介

Socket 是 网络传输的抽象概念。
一般我们常用的有Tcp SocketUDP Scoket, 和类Unix 系统(包括Mac)独有的 Unix Domain Socket(UDX)。

  • Tcp Socket 能够跨电脑进行通信,即使是在同一个电脑下的多进程间通信,也会通过网卡进行数据传输,如果本地网卡的环回网络被禁用, 则会导致通信失败。
  • Unix Domain Socket,使用的是Liunx 系统中万物皆文件的概念,和有名管道的操作差不多,都是在文本创建一个特有的文件,用来在两个进程间通信,两个进程分别写入和读取文件流中的数据,达到传输的目的。 和Tcp Socket不一样的是不用借助网卡通信,限制比较小,传输的效率高。

这里主要针对 Unix Domain Socket进行研究.


在终端使用 ls -ll /tmp/
可以看到红圈中我们demo创建的Unix Domain Socket 文件。
Unix Domain Socket 会在 在第一列将会显示类型 s
这里还有其他类型的文件。其中p表示命名管道文件,d表示目录文件,l表示符号连接文件,-表示普通文件,s表示socket文件,c表示字符设备文件,b表示块设备文件。
在这里插入图片描述

二:主要函数

1. int socket (int domain, int type, int protocol) 创建socket 对象

  • domain 选择 AF_UNIX, 代表 unix domain socket
  • type. 选择SOCK_STREAM, socket 流
  • protocol 填0, 由系统选择

2. int bind(int sockfd, const struct sockaddr* myaddr, socklen_t addrlen)

将socket 绑定到对应 ip 和 端口上

  • sockfd 前面返回的描述符
  • myaddr 包含 通信 对象 路径的struct, 这里创建的是 /tmp/jimbo_udx_server.sock
  • addrlen前一个stuct的长度

3. int listen(int sockfd, int backlog)

调用后,本地socket 文件的状态变更

  • sockfd 前面返回的描述符
  • backlog 此socket 接收的客户端的数量

4. int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen)

阻塞式等待客户端接入,客户端接入后返回。
传入serversockfd,返回接入后的sockfd.
后面两个参数代表接口客户端的地址及struct长度

5. int read(int sockfd, void *buf, int len, unsigned int flags)

接收客户端发来的数据

6. int write(int sockfd, const void *msg, int len, int flags)

服务器 往 客户端/服务器发送数据

7. int close(int sockfd) 或 Windows的 7. int closesocket(int sockfd)

关闭连接

三:demo代码

如下图,创建了两个进程,分别为服务器App, 客户端App.
UI 上点击发送按钮。 收到消息后可以在 控制台查看 输出。
在这里插入图片描述

1. 服务器端主要逻辑

  • 主要创建了socket一个 AF_UNIXSOCK_STREAM 组合的socket

  • remove(...) 删除以前的sock 文件

  • bind 将文件路径和 socket 对象绑定在一起

  • listen() 开始监听

  • 启动子线程,在线程内 阻塞等待客户端连接(accept),和接收客户端消息(read)

  • 启动客户端进程。 客户端内进行连接到这个服务器

  • 点击ui上的发送按钮,往客户端发送消息

    主要代码: ViewController.mm 文件代码

//
//  ViewController.m
//  Sockct_UDX_MainApp
//
//  Created by jimbo on 2024/1/5.
//#import "ViewController.h"
#include <sys/socket.h>const char * s_sock_path = "/tmp/jimbo_udx_server.sock";@interface ViewController ()
@property (weak) IBOutlet NSTextField *textLabel;@property (nonatomic, assign) int sfd;
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];/**int socket(int domain, int type, int protocol)AF_UNIX VS AF_INET(ipv4 tcp)SOCK_STREAM VS SOCK_DGRAM当protocol为0时,会自动选择type类型对应的默认协议。*/int sfd = socket(AF_UNIX, SOCK_STREAM, 0);self.sfd = sfd;if (sfd == -1) {perror("socket create failed!");return;}// 删除所有与路径名一致的既有文件,这样才能将 socket 绑定到这个路径名上if (remove(s_sock_path) == -1 && errno != ENOENT){perror("remove failed");return;}struct sockaddr_un addr  = {0};addr.sun_family = AF_UNIX;strcpy(addr.sun_path, s_sock_path);//bind 的时候会在文件路径创建响应的s_sock_path文件. (UI app 需要关闭沙盒才能有权限访问对应的路径)//当使用ls –ll列出时,UNIX domain socket 在第一列将会显示类型 s//扩展一下,这个位置还可以有其他几种选项:p、d、l、s、c、b和-://其中p表示命名管道文件,d表示目录文件,l表示符号连接文件,-表示普通文件,s表示socket文件,c表示字符设备文件,b表示块设备文件。int ret = bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));if (ret == -1) {perror("bind faild!");return;}ret = listen(sfd, 5);if (ret == -1) {perror("listen failed!");return;}NSThread *th = [[NSThread alloc] initWithTarget:self selector:@selector(subThreadWorker) object:nil];[th setName:@"udx thread"];[th start];NSLog(@"---start");//启动子进程 app client//启动子进程NSURL *subAppURL = [[NSBundle mainBundle] URLForResource:@"Sockct_UDX_SubApp" withExtension:@"app"];[[NSWorkspace sharedWorkspace] openURL:subAppURL configuration:[NSWorkspaceOpenConfiguration configuration] completionHandler:nil];
}- (void)subThreadWorker {NSLog(@"---subThreadWorker");ssize_t numRed = 0;static const int buffer_size = 100;char buffer[buffer_size];while (self.sfd != -1) {printf("服务器等待客户端%i连接...\n", self.sfd);//接受新链接, 并得到新的idself.sfd = accept(self.sfd, NULL, NULL);printf("收到客户端连接。 sfd:%i\n", self.sfd);if (self.sfd == -1) {perror("这是一个无效的连接!");break;}while ((numRed = read(self.sfd, buffer, buffer_size)) > 0) {printf("服务器收到客户端发的数据: %s\n", buffer);}if (numRed == -1) {perror("numRed == -1!");break;}if (close(self.sfd) == -1) {perror("close faild!");break;}printf("for over!\n");}printf("sub thread over!\n");//    exit(0);
}- (IBAction)sendMsgToClient:(id)sender {const  char *backBuffer = [self.textLabel.stringValue UTF8String];ssize_t sendLen =  write(self.sfd, backBuffer, strlen(backBuffer)+1);if (sendLen < 0) {printf("error:%i\n", errno);perror("服务器发送给客户端失败!reason:");} else {printf("服务器发送给客户端成功!len:%zi\n", sendLen);}
}@end

2. 客户端主要逻辑

  • 主要创建了socket一个 AF_UNIXSOCK_STREAM 组合的socket
  • connect(...) 使用带服务器创建的sock 路径/tmp/jimbo_udx_server.sock 的结构体,和 socket 对象进行连接。 这样双方通信就建立了
  • read(...)在子线程 阻塞式 等待服务器的消息.
  • write(..) UI 按钮点击后,往服务器发消息

主要代码: ViewController.mm 文件代码

//
//  ViewController.m
//  Sockct_UDX_SubApp
//
//  Created by jimbo on 2024/1/5.
//#import "ViewController.h"
#include <sys/socket.h>const char * s_sock_path = "/tmp/jimbo_udx_server.sock";@interface ViewController ()
@property (weak) IBOutlet NSTextField *textLabel;@property (nonatomic, assign) int sfd;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];int sfd = socket(AF_UNIX, SOCK_STREAM, 0);self.sfd = sfd;if (sfd == -1) {perror("socket create failed!");return;}/*// client 也可以同事绑定一个路径。自己又当客户端又当服务器const char * s_sock_path_client = "/tmp/jimbo_udx_client.sock";// 删除所有与路径名一致的既有文件,这样才能将 socket 绑定到这个路径名上if (remove(s_sock_path_client) == -1 && errno != ENOENT){perror("remove jimbo_udx_client.sock failed");return;}struct sockaddr_un addr_client  = {0};addr_client.sun_family = AF_UNIX;strcpy(addr_client.sun_path, s_sock_path_client);//bind 的时候会在文件路径创建响应的s_sock_path文件. (UI app 需要关闭沙盒才能有权限访问对应的路径)//当使用ls –l列出时,UNIX domain socket 在第一列将会显示类型 s//扩展一下,这个位置还可以有其他几种选项:p、d、l、s、c、b和-://其中p表示命名管道文件,d表示目录文件,l表示符号连接文件,-表示普通文件,s表示socket文件,c表示字符设备文件,b表示块设备文件。int ret = bind(sfd, (struct sockaddr *)&addr_client, sizeof(struct sockaddr_un));if (ret == -1) {perror("bind  addr_client faild!");return;}*/struct sockaddr_un addr = {0};addr.sun_family = AF_UNIX;strcpy(addr.sun_path, s_sock_path);NSLog(@"准备connect");int ret = connect(self.sfd, (const struct sockaddr *)&addr, sizeof(addr));if (ret == -1) {perror("connect faild!");return;}NSLog(@"connect成功");[NSThread detachNewThreadWithBlock:^{//单独线程监听服务器发回来的消息static const int buffer_size = 100;char buffer[buffer_size];while (self.sfd != -1) {printf("等待服务的回调...\n");ssize_t len = read(self.sfd, buffer, buffer_size);printf("收到的服务器回馈长度:%zi\n", len);if (len <= 0) {printf("read error:%i\n", errno);perror("read failed");
//                assert(false); //需要判断是否服务器已经断开了的情况。exit(0);}else {printf("服务器返回的数据:%s\n", buffer);}}printf("等待服务器回调线程结束!\n");}];}- (IBAction)sendMegToServer:(id)sender {//发送消息const char *buf = [self.textLabel.stringValue UTF8String];size_t numWrite = strlen(buf) + 1;ssize_t writeSize = write(self.sfd, buf, numWrite);printf("numWrite: %zu writeSize:%zi\n", numWrite, writeSize);if (writeSize == -1) {perror("write failed!");return;}
}- (void)dealloc {if (self.sfd > 0) {NSLog(@"关闭 sfd");close(self.sfd);self.sfd = -1;}
}@end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650937.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Scratch:启蒙少儿编程的图形化魔法

在当今这个数字化时代&#xff0c;编程已经成为了一项重要的基础技能。就像学习阅读和写作一样&#xff0c;掌握编程能够打开通往未来世界的大门。对于孩子们来说&#xff0c;Scratch作为一种图形化编程语言&#xff0c;不仅简单有趣&#xff0c;而且非常适合作为编程学习的入门…

科技助力“双碳”:墨水屏电子桌牌在绿色办公中的作用

随着科技的发展&#xff0c;人们对绿色环境可持续发展也越来越重视&#xff0c;所以&#xff0c;我国在几年前&#xff0c;就提出了“双碳”政策&#xff08;即碳达峰与碳中和的简称。2020年9月中国明确提出2030年“碳达峰”与2060年“碳中和”目标&#xff09;&#xff0c;而作…

单调栈第二天(还没写完)

503.下一个更大元素II 力扣题目链接(opens new window) 给定一个循环数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&#xff09;&#xff0c;输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更…

卸载软件Geek Uninstaller,MySQl安装不成功

最近刷最右的时候&#xff0c;看到两个帖子都是MySQl安装过程总是出现问题。大概两年前我也遇到了这个问题&#xff0c;推荐一款软件。 是因为在安装的过程之中&#xff0c;出现了问题。然后你再进行安装的时候&#xff0c;没有完全将原来安装的软件卸载掉&#xff0c;导致有注…

垃圾填埋气体监测与告警一体化环保监测5G云网关

数字化时代数据采集和传输我认为变得非常重要。为了满足这一需求&#xff0c;我们推出了一款具备多种功能的数据采集器。这款产品不仅集成了8DI干湿节点、4DO继电器、6AI电流/电压型传感器&#xff0c;还支持与多个云平台进行上行对接。通过这些功能&#xff0c;用户可以轻松实…

深入浅出理解目标检测的非极大值抑制(NMS)

一、参考资料 物体检测中常用的几个概念迁移学习、IOU、NMS理解 目标定位和检测系列&#xff08;3&#xff09;&#xff1a;交并比&#xff08;IOU&#xff09;和非极大值抑制&#xff08;NMS&#xff09;的python实现 Pytorch&#xff1a;目标检测网络-非极大值抑制(NMS) …

机器学习整理

绪论 什么是机器学习&#xff1f; 机器学习研究能够从经验中自动提升自身性能的计算机算法。 机器学习经历了哪几个阶段&#xff1f; 推理期&#xff1a;赋予机器逻辑推理能力 知识期&#xff1a;使机器拥有知识 学习期&#xff1a;让机器自己学习 什么是有监督学习和无监…

CubeMX生成工程文件夹解释

使用CubeMXKeil的工程&#xff0c;物理文件夹结构如下&#xff1a; 文件夹、文件&#xff0c;众多&#xff0c;但我们平时使用到的&#xff0c;主要是两个入口文件&#xff0c;即以下的&#xff1a;1和2. 1、***.uvprojx 位置&#xff1a;工程目录\MDK-ART文件夹下。 Keil的工…

【C++】STL和vector容器

STL和vector容器 基本概念六大组件容器算法迭代器容器算法迭代器 vector容器基本概念vector构造函数赋值vector的容量和大小vector插入与删除vector存取数据函数原型 vector互换容器vector预留空间vector容器嵌套容器 基本概念 长久以来&#xff0c;软件届一直希望建立一种可重…

基于 java+springboot+mybatis电影售票网站管理系统前台+后台设计和实现

基于 javaspringbootmybatis电影售票网站管理系统前台后台设计和实现 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承…

国内首个!亚信安全获得CCRC数据分类分级产品认证证书

亚信安全信数数据分类分级系统AISDC V1.0&#xff0c;荣获中国网络安全审查认证和市场监管大数据中心颁发的首个数据分类分级产品IT产品信息安全认证证书&#xff01;标志着亚信安全在大数据安全领域的强大技术实力以及专业研究&#xff0c;正式获得国内数据分类分级产品评定的…

通过LiveNVR实现海康大华华为宇视等监控摄像头在服务器上录像存储,并web无插件直播和回放

支持云端录像服务器上面集中录像存储在部署LiveNVR的服务器上面 1、流媒体服务软件2、配置开启录像(云端录像)3、录像回看(云端录像)3.1、查看录像3.1.1、时间轴视图3.1.2、列表视图 4、云端录像相关接口5、如何分享时间轴录像回看&#xff1f;6、iframe集成示例7、RTSP/HLS/FL…

centos 7 增加临时路由及永久路由

centos 7 增加临时路由及永久路由 如果增加临时路由&#xff0c;要先安装net-tools , sudo yum install net-tools route add -net 10.1.0.0 gw 10.1.1.1 netmask 255.255.0.0 意思是增加了一条动态路由&#xff0c;网关10.1.1.1 ,10.1.x.x 的所有ip都走这个网关 此种方式&am…

[框架系列]-[通用lock框架]集成及具体配置使用

目录 一&#xff1a;框架集成 1.添加pom依赖 2.开启lock配置 二&#xff1a;配置详细介绍 1.配置清单 2.具体配置介绍 &#xff08;1&#xff09;implementer &#xff08;2&#xff09;type &#xff08;3&#xff09;transactionStrategy &#xff08;4&#xff09…

Dev-Home:又一个开发人员控制中心神器,微软官方出品!

前两周&#xff0c;微软针对开发人员推出的windows控制中心&#xff1a;Dev-Home&#xff0c;迎来了0.9的预览版&#xff0c;这次重点的更新是支持Window 10了&#xff0c;之前一直都只支持Windows 11。 Dev-Home核心有两个功能&#xff1a;系统监控小组件和Gtihub扩展小组件。…

ISO 14229和UDS:汽车诊断的黄金标准

UDS简介&#xff1a; UDS是Unified Diagnostic Services的缩写&#xff0c;全名统一诊断服务。它是一种用于汽车电子控制单元&#xff08;ECU&#xff09;之间进行诊断和通信的标准协议&#xff0c;属于ISO 14229标准的一部分。 UDS的起源和背景&#xff1a; UDS的起源可以追…

一个处理Range List的面试题解法

大纲 题目解法Rangeaddremove ToolsRangeListaddremove 代码 最近看到一个比较有意思的面试题。题目不算难&#xff0c;但是想把效率优化做好&#xff0c;也没那么容易。 我们先看下题目 题目 // Task: Implement a class named RangeList // A pair of integers define a ra…

【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]

前言 大家好吖&#xff0c;欢迎来到 YY 滴 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Linux》…

JavaEE-自定义SSM-编写核心-解析yml文件

3.3.1 加载yml文件 编写yaml工厂&#xff0c;用于加载yml文件 package com.czxy.yaml;import java.io.InputStream;/*** 用于处理 application.yml文件* 1. 加载application.yml文件* 2. yaml工具类进行解析* Map<String, Map<String, Map<....>> >* …

Linux使用二进制包安装MySQL

目录 一、软件包下载 二、上传软件包到Linux根目录 1、使用xftp将软件包上传到根目录 2、解压缩 三、准备工作 四、初始化软件 五、设置MySQL的配置文件 六、配置启动脚本 一、软件包下载 官网下载&#xff1a;MySQL :: Download MySQL Community Server 二、上传软件…