iOS 通讯之FTP

作者: NextStepPeng | 来源:发表于2019-07-16 15:12 被阅读0次

    背景

    因项目需要,需要在规定的时间内根据特定的信号,将大量的图片和文件下载/上传到iOS本地/服务器进行实时渲染,因之前也尝试了socket通讯,但还是会引起通讯阻塞(因还有大量接口需要采用socket通讯)。故采用FTP协议传输。

    FTP

    FTP(File Transfer Protocol,文件传输协议) 是 TCP/IP 协议组中的协议之一。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。FTP允许用户以文件操作的方式(如文件的增、删、改、查、传送等)与另一主机相互通信

    联调工具

    • 推荐使用工具: FileZilla
    • 也可以用终端ssh指令,将特定的文件上传/下载到FTP服务器,做完辅助测试用
      上传
    scp "需要上传的文件" root@182.168.1.88:/home/pi/App
    

    下载,先登录到远程设备(我这边是Linux系统服务器)

    scp "需要下载的文件" root@182.168.1.3:/Users/peng***/Documents/1-21
    

    FTP传输

    因我这边项目需要只需要上传和下载文件(登录每次请求的时候携带用户名和密码),故FTP的其它功能没有封装(采用CFWiterRef),大同小异。

    • 上传
     CFWriteStreamRef writeStreamRef = CFWriteStreamCreateWithFTPURL(NULL, ( __bridge CFURLRef) url);
    //url :上传的地址
            CFWriteStreamSetProperty(writeStreamRef,
                                     kCFStreamPropertyFTPAttemptPersistentConnection,
                                     kCFBooleanFalse);
            
            CFWriteStreamSetProperty(writeStreamRef, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            CFWriteStreamSetProperty(writeStreamRef, kCFStreamPropertyFTPUsePassiveMode, kCFBooleanTrue);
            CFWriteStreamSetProperty(writeStreamRef, kCFStreamPropertyFTPFetchResourceInfo, kCFBooleanTrue);
            CFWriteStreamSetProperty(writeStreamRef, kCFStreamPropertyFTPUserName, (__bridge CFStringRef) self.ftpUsername);
            CFWriteStreamSetProperty(writeStreamRef, kCFStreamPropertyFTPPassword, (__bridge CFStringRef) self.ftpPassword);
            
            self.commandStream = ( __bridge_transfer NSOutputStream *) writeStreamRef;
    //得到输出流
            
            self.commandStream.delegate = self;
            [self performSelector:@selector(scheduleInCurrentThread:)
                         onThread:[[self class] networkThread]
                       withObject:self.commandStream
                    waitUntilDone:YES];
            
            [self.commandStream open]
    
    • 下载
    CFReadStreamRef readStreamRef = CFReadStreamCreateWithFTPURL(NULL, ( __bridge CFURLRef) url);
            CFReadStreamSetProperty(readStreamRef,
                                    kCFStreamPropertyFTPAttemptPersistentConnection,
                                    kCFBooleanFalse);
            
            CFReadStreamSetProperty(readStreamRef, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            CFReadStreamSetProperty(readStreamRef, kCFStreamPropertyFTPUsePassiveMode, kCFBooleanTrue);
            CFReadStreamSetProperty(readStreamRef, kCFStreamPropertyFTPFetchResourceInfo, kCFBooleanTrue);
            CFReadStreamSetProperty(readStreamRef, kCFStreamPropertyFTPUserName, (__bridge CFStringRef) self.ftpUsername);
            CFReadStreamSetProperty(readStreamRef, kCFStreamPropertyFTPPassword, (__bridge CFStringRef) self.ftpPassword);
            //
            CFReadStreamSetProperty(readStreamRef, kCFStreamPropertyFTPProxy, kCFBooleanTrue);
            //
            
            self.dataStream = ( __bridge_transfer NSInputStream *) readStreamRef;
            self.dataStream.delegate = self;
            if (self.dataStream == nil) {
                
                [self.delegate ftpError:self withErrorCode:FTPClientCantReadStream];
                
            }
            
            [self performSelector:@selector(scheduleInCurrentThread:)
                         onThread:[[self class] networkThread]
                       withObject:self.dataStream
                    waitUntilDone:YES];
           
    //        [self.dataStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
            [self.dataStream open];
    
    • 输入输出流回调处理
    - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
    // An NSStream delegate callback that's called when events happen on our
    // network stream.
    {
    #pragma unused(aStream)
         switch (eventCode) {
            case NSStreamEventOpenCompleted: {
                self.didOpenStream = true;
                if ([self.currentOperation isEqualToString:@"GET"]){
                    self.maximumSize = [[aStream propertyForKey:(id)kCFStreamPropertyFTPResourceSize] integerValue];
                    //NSLog(@"%luself.maximumSize:%d: %f",self.dType,self.currentIndex,self.maximumSize );
                }
                self.uploadBytesTotal = 0;
                self.bytesRemaining = 0;
                self.bytesTotal = 0;
            } break;
            case NSStreamEventHasBytesAvailable: {
                if ([self.currentOperation isEqualToString:@"GET"]){
                   
                   NSData *data = [self read];
                   if (data) {
                      [self.receivedData appendData:data];
                   }else {
                       NSLog(@"流出现异常");
                       [self.delegate ftpError:self withErrorCode:FTPClientCantReadStream];
                       [self closeAll];
                   }
                }
            } break;
    
            case NSStreamEventHasSpaceAvailable: {
                    if (self.bytesRemaining == 0) {
                        self.sentData = [NSData dataWithContentsOfFile:self.uploadFilePath];
                        
                        self.bytesRemaining = [_sentData length];
                        self.bytesIndex = 0;
                        
                        if (self.sentData == nil) {
                            [self.delegate ftpUploadFinishedWithSuccess:self];
                        }
                        
                    }
                    NSUInteger nextPackageLength = MIN(kGRDefaultBufferSize, self.bytesRemaining);
                    NSRange range = NSMakeRange(self.bytesIndex, nextPackageLength);
                
                    NSData *packetToSend = [self.sentData subdataWithRange: range];
                
                    [self uploadWrite:packetToSend];
                
                    self.bytesIndex += self.bytesThisIteration;
                    self.bytesRemaining -= self.bytesThisIteration;
                
                
            } break;
            case NSStreamEventErrorOccurred: {
                
                [self.delegate ftpError:self withErrorCode:FTPClientCantOpenStream];
                
                [self closeAll];
            } break;
            case NSStreamEventEndEncountered: {
                // ignore
                if ([self.currentOperation isEqualToString:@"GET"]){
                    //NSLog(@"%luself.maximumSizeEnd:%d:%.2f",(unsigned long)self.dType,self.currentIndex,self.maximumSize );
                    //NSLog(@"%luself.maximumSizeData:%d:%lu",(unsigned long)self.dType,self.currentIndex,self.receivedData.length );
                    if (self.maximumSize != self.receivedData.length) {
                        //下载异常
                        NSLog(@"下载异常:%d",self.currentIndex);
                        [self.delegate ftpError:self withErrorCode:FTPClientCantOpenStream];
                        
                        [self closeAll];
                        return;
                    }
                    if ([self downOk]) {
                        if ([self.delegate respondsToSelector:@selector(ftpDownloadFinishedWithSuccess:withIndex:withPath:withData:)]) {
                         
                            [self.delegate ftpDownloadFinishedWithSuccess:self withIndex:self.currentIndex withPath:self.localname withData:self.receivedData];
                        }
                        
                    }
                    
                    
                    [self closeAll];
                }
                if ([self.currentOperation isEqualToString:@"upload"]) {
                    [self.delegate ftpError:self withErrorCode:FTPClientCantOpenStream];
                    [self closeAll];
                }
            } break;
            default: {
                assert(NO);
            } break;
        }
    }
    
    • 这个demo里面异常处理以及流处理中都用到了RunLoop处理RunLoop 说明

    demo

    相关文章

      网友评论

        本文标题:iOS 通讯之FTP

        本文链接:https://www.haomeiwen.com/subject/fevzkctx.html