前言
进程通信方案会有以下几种(根据具体场景进行选择)
1:Universal Links、URL Scheme 常用的App间传值方式,常见于分享和app间跳转。
2:Keychain 借助系统类 KeychainItemWrapper来使用。常见于免登陆 (同公司产品间)
3:UIPasteboard 粘贴板。 淘宝的链接分享。
4:UIDocumentInteractionController 常用于文件的分享
5:local socket
(本文内容)
如果你对IPC不了解,可以先看下这篇文章:Inter process Communication
https://blog.csdn.net/z929118967/article/details/77981259
iOS【 ASO项目使用的技术】之 Inter process Communication
登录 iTunes Store 这个输入框的弹出流程是由itunesstored 控制,process:SpringBoard 进行处理,采用SBUserNotificationAlert的方式进行进程间的消息传递。
I 、方案案例:local socket
采用Local Socket方案(TCP)创建服务端和客户端从而达到通讯效果。
- 基于GCDAsyncSocket提供的解决方案
基于 CFSocket、GCD 进行的封装,支持 TCP 和 UDP
platform :ios, '8.0' inhibit_all_warnings! #use_frameworks! target 'localScoket' do pod 'CocoaAsyncSocket' end target 'localScoket4client' do pod 'CocoaAsyncSocket' end
1.1 基础知识:Socket 通讯过程
- CFSocket(纯 C)
苹果对对底层 BSD Socket 进行轻量级的封装。API:CFSocekt 用于建立连接,CFStream 用于读写数据。
- tcp
UDP
TCP 的三次握手建立连接
TCP 的四次挥手
释放连接
- 先挥手再握手(先断开再连接)
- 先握手再挥手(先连接再断开)
1.2 serverSocket
#import <GCDAsyncSocket.h> @interface ViewController () { GCDAsyncSocket *_serverSocket; } @property(strong,nonatomic)NSMutableArray *clientSocket; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _clientSocket = [NSMutableArray array]; //创建服务端的socket,注意这里的是初始化的同时已经指定了delegate _serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; [self startChatServer]; } -(void)startChatServer{ //打开监听端口 NSError *err; [_serverSocket acceptOnPort:12345 error:&err]; if (!err) { NSLog(@"Server 服务开启成功"); }else{ NSLog(@"Server 服务开启失败"); } } #pragma mark 有客户端建立连接的时候调用 -(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{ //sock为服务端的socket,服务端的socket只负责客户端的连接,不负责数据的读取。 newSocket为客户端的socket NSLog(@"服务端的socket %p 客户端的socket %p",sock,newSocket); //保存客户端的socket,如果不保存,服务器会自动断开与客户端的连接(客户端那边会报断开连接的log) NSLog(@"Server %s",__func__); [self.clientSocket addObject:newSocket]; //newSocket为客户端的Socket。这里读取数据 [newSocket readDataWithTimeout:-1 tag:100]; } #pragma mark 服务器写数据给客户端 -(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"Server %s",__func__); [sock readDataWithTimeout:-1 tag:100]; } #pragma mark 接收客户端传递过来的数据 -(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ //sock为客户端的socket NSLog(@"Server 客户端的socket %p",sock); //接收到数据 NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"Server receiverStr :%@",receiverStr); // 把回车和换行字符去掉,接收到的字符串有时候包括这2个,导致判断quit指令的时候判断不相等 receiverStr = [receiverStr stringByReplacingOccurrencesOfString:@"\r" withString:@""]; receiverStr = [receiverStr stringByReplacingOccurrencesOfString:@"\n" withString:@""]; //判断是登录指令还是发送聊天数据的指令。这些指令都是自定义的 //登录指令 if([receiverStr hasPrefix:@"iam:"]){ // 获取用户名 NSString *user = [receiverStr componentsSeparatedByString:@":"][1]; // 响应给客户端的数据 NSString *respStr = [user stringByAppendingString:@"has joined"]; [sock writeData:[respStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]; } //聊天指令 if ([receiverStr hasPrefix:@"msg:"]) { //截取聊天消息 NSString *msg = [receiverStr componentsSeparatedByString:@":"][1]; [sock writeData:[msg dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]; } //quit指令 if ([receiverStr isEqualToString:@"quit"]) { //断开连接 [sock disconnect]; //移除socket [self.clientSocket removeObject:sock]; } NSLog(@"Server %s",__func__); }
1.3 clientSocket
这部分代码请看CSDN原文,或者下载demo