0
点赞
收藏
分享

微信扫一扫

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)

前言

进程通信方案会有以下几种(根据具体场景进行选择)

1: Universal Links、URL Scheme 常用的App间传值方式,常见于分享和app间跳转。

2: Keychain 借助系统类 KeychainItemWrapper来使用。常见于免登陆 (同公司产品间)

3: UIPasteboard 粘贴板。 淘宝的链接分享。

4: UIDocumentInteractionController 常用于文件的分享

5:​​ local socket​​(本文内容)

如果你对IPC不了解,可以先看下这篇文章: Inter process Communication

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_客户端

登录 iTunes Store 这个输入框的弹出流程是由itunesstored 控制,process:SpringBoard 进行处理,采用SBUserNotificationAlert的方式进行进程间的消息传递。

I 、方案案例:local socket

采用Local Socket方案(TCP)创建服务端和客户端从而达到通讯效果。

  • 基于GCDAsyncSocket提供的解决方案

基于 CFSocket、GCD 进行的封装,支持 TCP 和 UDP

'8.0'
inhibit_all_warnings!

#use_frameworks!
target 'localScoket' do
pod 'CocoaAsyncSocket'
end

target 'localScoket4client' do
pod 'CocoaAsyncSocket'

1.1 基础知识: Socket 通讯过程

  • CFSocket(纯 C)

苹果对对底层 BSD Socket 进行轻量级的封装。

API: CFSocekt 用于建立连接,CFStream 用于读写数据。

  • tcp

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_.net_02

  • UDP

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_客户端_03

  • TCP 的三次握手建立连接

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_.net_04

  • TCP 的四次​​挥手​​释放连接

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_服务端_05

  • 先挥手再握手(先断开再连接)

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_iOS_06

  • 先握手再挥手(先连接再断开)

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_.net_07

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
-(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
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(@"Server %s",__func__);
[sock readDataWithTimeout:-1 tag:100];
}

#pragma
-(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__);
}

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_客户端_08

1.3 clientSocket

iOS进程间的实时通讯方案: local socket(解决扩展和容器应用的实时通讯问题)_iOS_09

1.4 完整demo

see also

  • tweak 项目 快速搭建CocoaAsyncSocket(建连、断开、重连、心跳、通用请求)

文章作者

文章标题

文章链接

公众号:iOS逆向

进程间的实时通讯



举报

相关推荐

0 条评论