iOS進程通信之LocalSocket

iOS進程通信

在iOS中,進程通信的方式有很多種;下面先列舉下常用的幾種方式:

  • URL scheme
  • Keychain
  • APP Group
  • UIPasteBoard
  • LocalSocket

此篇著重了解LocalSocket,首先我們需要知道客戶端、服務端的區(qū)別;

  • 服務端:需要在本地端口進行TCP的綁定、監(jiān)聽
  • 客戶端:獲取服務端同一個端口,進行連接

當兩端建立連接后,接著就可以去發(fā)送消息了;

Broadcast Upload Extension為例;(這里使用OC的第三方庫GCDAsyncSocket

  • **在主程序中,我們是以服務端去設置socket **

開啟socket服務

// 開啟socket服務
- (void)startSocketService {
    if (self.serverSocket != nil) {
        return;
    }
    self.serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    self.serverSocket.autoDisconnectOnClosedReadStream = YES;
    __autoreleasing NSError *error = nil;
    BOOL result = [self.serverSocket acceptOnInterface:@"localhost" port:8080 error:&error];
    if(error || !result){
        NSLog(@"server socket result:%@ error:%@", error, @(result));
    }else {
        NSLog(@"server socket:%@ listen", self.serverSocket);
    }
}

停止socket服務

// 停止socket服務
- (void)stopSocketService {
    if (self.serverSocket != nil) {
        [self.serverSocket disconnect];
    }
    self.serverSocket = nil;
}
  • 在Extension程序中,我們是以客戶端去設置socket

連接socket

// 連接socket
- (void)socketConnect {
    if (self.videoSocket != nil) {
        self.videoSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:[self.class SEND_VIDEO_SERIAL_QUEUE]];
    }
    if (!self.videoSocket.isConnected) {
        NSError *error;
        [self.videoSocket connectToHost:@"localHost" onPort:8080 error:&error];
        [self.videoSocket readDataWithTimeout:-1 tag:10086];
    }
}

斷開socket

// 斷開socket
- (void)socketDisConnect {
    [self.videoSocket disconnect];
    self.videoSocket = nil;
}

socket寫入數(shù)據(jù)

// 發(fā)送數(shù)據(jù)
- (void)sendVideoSampleBuffer:(nonnull CMSampleBufferRef)sampleBuffer {
    CFTimeInterval currentTime = CACurrentMediaTime();
    if (currentTime - self.lastTimeInterval < self.frameInterval) {
        return;
    }
    self.lastTimeInterval = currentTime;
    @autoreleasepool {
        NSNumber *orientation = nil;
        if (@available(iOS 11.0, *)) {
            CFStringRef orientationKey = (__bridge CFStringRef)RPVideoSampleOrientationKey;
            orientation = (NSNumber *)CMGetAttachment(sampleBuffer,orientationKey,NULL);
        }
        size_t length = 0;
        void *sendData = [TScreenShareBroadcasterTool sampleBufferToData:sampleBuffer targetSize:self.options.targetFrameSize orientation:orientation length:&length];
        dispatch_async([[self class] SEND_VIDEO_SERIAL_QUEUE], ^{

            NSData *data = [NSData dataWithBytes:sendData length:length];
            [self.videoSocket writeData:data withTimeout:5 tag:10086];
            free(sendData);
        });
    }
}

socket回調

#pragma mark - GCDAsyncSocketDelegate
//已經(jīng)連接到服務器
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(nonnull NSString *)host port:(uint16_t)port{
    NSLog(@"連接成功 : %@---%d",host,port);
    //連接成功或者收到消息,必須開始read,否則將無法收到消息,
    //不read的話,緩存區(qū)將會被關閉
    // -1 表示無限時長 ,永久不失效
    [sock readDataWithTimeout:-1 tag:10086];
}

// 連接斷開
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    NSLog(@"斷開 socket連接 原因:%@",err);
    
    [self.videoSocket disconnect];
    self.videoSocket = nil;
    [self socketConnect];
}

//已經(jīng)接收服務器返回來的數(shù)據(jù)
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    NSLog(@"接收到tag = %ld : %ld 長度的數(shù)據(jù)",tag,data.length);
    //連接成功或者收到消息,必須開始read,否則將無法收到消息
    //不read的話,緩存區(qū)將會被關閉
    // -1 表示無限時長 , tag
    [sock readDataWithTimeout:-1 tag:10086];
}

//消息發(fā)送成功 代理函數(shù) 向服務器 發(fā)送消息
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    NSLog(@"%ld 發(fā)送數(shù)據(jù)成功",tag);
}

由于使用socket,所以需要處理粘包的情況。目前粘包解決方案基本上都是通用的。
粘包解決方案:
給每個數(shù)據(jù)包添加頭部,頭部中包含數(shù)據(jù)包長度,這樣接收到數(shù)據(jù)后,通過讀取頭部的長度字段,便知道每一個數(shù)據(jù)包的實際長度,然后根據(jù)實際的長度去讀取對應的長度的數(shù)據(jù),這樣便可以獲取正確的數(shù)據(jù);
具體做法如下:
封包:給每個包添加包頭,包頭包含數(shù)據(jù)的長度
拆包:將數(shù)據(jù)包塞入環(huán)形緩沖區(qū),比較緩存區(qū)的長度是否大于總長度,大于則取出包頭獲取數(shù)據(jù)的長度,并根據(jù)長度取出正確的數(shù)據(jù),處理完后將處理后的數(shù)據(jù)移出緩沖區(qū);

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容