iOS 通訊之FTP

背景

因項(xiàng)目需要间景,需要在規(guī)定的時(shí)間內(nèi)根據(jù)特定的信號(hào),將大量的圖片和文件下載/上傳到iOS本地/服務(wù)器進(jìn)行實(shí)時(shí)渲染寨典,因之前也嘗試了socket通訊调鬓,但還是會(huì)引起通訊阻塞(因還有大量接口需要采用socket通訊)。故采用FTP協(xié)議傳輸补憾。

FTP

FTP(File Transfer Protocol,文件傳輸協(xié)議) 是 TCP/IP 協(xié)議組中的協(xié)議之一漫萄。FTP協(xié)議包括兩個(gè)組成部分,其一為FTP服務(wù)器,其二為FTP客戶端。FTP允許用戶以文件操作的方式(如文件的增盈匾、刪腾务、改、查削饵、傳送等)與另一主機(jī)相互通信

聯(lián)調(diào)工具

  • 推薦使用工具: FileZilla
  • 也可以用終端ssh指令岩瘦,將特定的文件上傳/下載到FTP服務(wù)器,做完輔助測(cè)試用
    上傳
scp "需要上傳的文件" root@182.168.1.88:/home/pi/App

下載窿撬,先登錄到遠(yuǎn)程設(shè)備(我這邊是Linux系統(tǒng)服務(wù)器)

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

FTP傳輸

因我這邊項(xiàng)目需要只需要上傳和下載文件(登錄每次請(qǐng)求的時(shí)候攜帶用戶名和密碼)启昧,故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];
  • 輸入輸出流回調(diào)處理
- (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(@"流出現(xiàn)異常");
                   [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;
    }
}
  • 這個(gè)demo里面異常處理以及流處理中都用到了RunLoop處理RunLoop 說明

demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末密末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宰啦,更是在濱河造成了極大的恐慌苏遥,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赡模,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡师抄,警方通過查閱死者的電腦和手機(jī)漓柑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叨吮,“玉大人辆布,你說我怎么就攤上這事〔杓” “怎么了锋玲?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)涵叮。 經(jīng)常有香客問我惭蹂,道長(zhǎng)伞插,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任盾碗,我火速辦了婚禮媚污,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘廷雅。我一直安慰自己耗美,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布航缀。 她就那樣靜靜地躺著商架,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芥玉。 梳的紋絲不亂的頭發(fā)上蛇摸,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音飞傀,去河邊找鬼皇型。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砸烦,可吹牛的內(nèi)容都是我干的弃鸦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼幢痘,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼唬格!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颜说,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤购岗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后门粪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喊积,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年玄妈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乾吻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拟蜻,死狀恐怖绎签,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酝锅,我是刑警寧澤诡必,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站搔扁,受9級(jí)特大地震影響爸舒,放射性物質(zhì)發(fā)生泄漏蟋字。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一碳抄、第九天 我趴在偏房一處隱蔽的房頂上張望愉老。 院中可真熱鬧,春花似錦剖效、人聲如沸嫉入。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咒林。三九已至,卻和暖如春爷光,著一層夾襖步出監(jiān)牢的瞬間垫竞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工蛀序, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留欢瞪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓徐裸,卻偏偏與公主長(zhǎng)得像遣鼓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子重贺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容