ページ 1 / 1
[objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月24日(火) 17:39
by matunon
質問させていただきます。
現在、FTP通信を用いて、サーバからiPhoneへとCSV形式のデータをダウンロードできるようにしようと思っています。
ダウンロードする処理自体は完成し、テストサーバを用いてみたところきちんと機能しました。
ですが、本番用のサーバではうまくいきませんでした。
FTPクライアントソフトを用いても本番用のサーバではうまくいかなかったので、原因を調べたところ、
アクティブモードとパッシブモードの違いである事がわかりました。(因に、パッシブモードでは通信失敗、アクティブモードでは成功しました。)
そこで質問なのですが、現在NSURLConectionをもちいてダウンロードしているのですが、通信モードを指定する事は可能なのでしょうか?
もし出来ないのであれば、アクティブモードで通信するにはどうすれば良いでしょうか?
出来れば、質問への答えとともに、どの部分をいじれば良いか、またはどのクラスを使えば良いかを教えていただきたいです。
相互リンク
yahoo知恵袋
http://detail.chiebukuro.yahoo.co.jp/qa ... 1130995266
Re: [objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月24日(火) 18:20
by h2so5
Re: [objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月24日(火) 22:59
by matunon
指示された記事をもとにクラスを作成してみたのですが、エラーが出てしまいます。
► スポイラーを表示
コード:
static const size_t kBufferSize = 1000000;
@implementation FTPDownload
- (void)download{
@autoreleasepool {
NSURL *fileURL = [NSURL fileURLWithPath:@"ftp://splanet:spadmin2013$@luna.aap-skynet.jp/naisen.csv"];
CFReadStreamRef reaadStream;
ここでEXC_BAD_ACCESS code=1,0x0 が表示されます
reaadStream = CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef)fileURL);
assert(reaadStream != NULL);
if (reaadStream) {
//ストリームを開く
BOOL shouldContinue;
shouldContinue = CFReadStreamOpen(reaadStream);
if (!shouldContinue) {
NSLog(@"Couldn't open the stream");
}
//読み込んだバイト列を格納するデータを作成する
NSMutableData *data = [NSMutableData dataWithCapacity:0];
unsigned char buf[kBufferSize];
//読み込み処理を繰り返すループ
while (shouldContinue) {
//ストリームに読み込んでいないデータがあるかチェックする
if (CFReadStreamHasBytesAvailable(reaadStream)) {
//バッファに読み込む
CFIndex numOfBytes;
numOfBytes = CFReadStreamRead(reaadStream,
buf,
kBufferSize);
if (numOfBytes > 0) {
//バッファに読み込めた
[data appendBytes:buf
length:numOfBytes];
}
else if (numOfBytes == 0) {
//ストリームの状態を取得する
CFStreamStatus status;
status = CFReadStreamGetStatus(reaadStream);
if (status == kCFStreamStatusAtEnd) {
//全データ読み込み完了
shouldContinue = NO;
//ローカルファイルへのURLを作成する
NSString *paths = [NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory,
NSUserDomainMask,
YES)lastObject];
paths = [paths stringByAppendingPathComponent:@"naisen.csv"];
//読み込んだデータをファイルに出力する
[data writeToFile:paths
atomically:YES];
}
}
else{
//エラー発生
NSLog(@"Error occurred¥n");
}
}
else{
}
}
//ストリームを閉じる
CFReadStreamClose(reaadStream);
//ストリームを解放する
CFRelease(reaadStream);
}
}
}
@end
Re: [objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月25日(水) 11:37
by matunon
コードを改造してみました。
今回はダウンロードのみ欲しいのでマネージャークラスには変更を加えず、getcontorollerクラスを用いてみました。
エラーは出ないのですがダウンロードは出来てません。
おそらく通信モードが原因なのですが指定する場所が分かりません。
CFreadStreamのsetpropertyメソッドのようなものが存在するのかと思っていたのですが・・・・。
コード:
#import "GetFTP.h"
#import "NetworkManager.h"
#include <CFNetwork/CFNetwork.h>
@interface GetFTP () <NSStreamDelegate>
@property (nonatomic, assign, readonly ) BOOL isReceiving;
@property (nonatomic, strong, readwrite) NSInputStream *networkStream;
@property (nonatomic, copy, readwrite) NSString *filePath;
@property (nonatomic) NSData *downloadData;
@property (nonatomic, strong, readwrite) NSOutputStream *fileStream;
@end
@implementation GetFTP
- (void)receiveDidStart
{
// Clear the current image so that we get a nice visual cue if the receive fails.
[[NetworkManager sharedInstance] didStartNetworkOperation];
}
- (void)updateStatus:(NSString *)statusString
{
assert(statusString != nil);
}
- (void)receiveDidStopWithStatus:(NSString *)statusString
{
if (statusString == nil) {
assert(self.filePath != nil);
NSLog(@"GET succeeded");
}
[[NetworkManager sharedInstance] didStopNetworkOperation];
}
#pragma mark * Core transfer code
// This is the code that actually does the networking.
- (BOOL)isReceiving
{
return (self.networkStream != nil);
}
- (void)startReceive
// Starts a connection to download the current URL.
{
NSLog(@"startReceive Start");
BOOL success;
NSURL * url;
assert(self.networkStream == nil); // don't tap receive twice in a row!
assert(self.fileStream == nil); // ditto
assert(self.filePath == nil); // ditto
// First get and check the URL.
url = [[NetworkManager sharedInstance] smartURLForString:@"ftp://username:password@myserver/vv.csv"];
success = (url != nil);
// If the URL is bogus, let the user know. Otherwise kick off the connection.
if ( ! success) {
NSLog(@"Invalid URL");
} else {
NSLog(@"OK");
// Open a stream for the file we're going to receive into.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"naisen.csv"]];
assert(self.filePath != nil);
self.fileStream = [NSOutputStream outputStreamToFileAtPath:self.filePath append:NO];
assert(self.fileStream != nil);
[self.fileStream open];
// Open a CFFTPStream for the URL.
self.networkStream = CFBridgingRelease(CFReadStreamCreateWithFTPURL(NULL,
(__bridge CFURLRef)url));
assert(self.networkStream != nil);
self.networkStream.delegate = self;
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream open];
// Tell the UI we're receiving.
[self receiveDidStart];
}
}
- (void)stopReceiveWithStatus:(NSString *)statusString
// Shuts down the connection and displays the result (statusString == nil)
// or the error status (otherwise).
{
if (self.networkStream != nil) {
[self.networkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.networkStream.delegate = nil;
[self.networkStream close];
self.networkStream = nil;
}
if (self.fileStream != nil) {
[self.fileStream close];
self.fileStream = nil;
}
[self receiveDidStopWithStatus:statusString];
self.filePath = nil;
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
// An NSStream delegate callback that's called when events happen on our
// network stream.
{
#pragma unused(aStream)
assert(aStream == self.networkStream);
switch (eventCode) {
case NSStreamEventOpenCompleted: {
[self updateStatus:@"Opened connection"];
} break;
case NSStreamEventHasBytesAvailable: {
NSInteger bytesRead;
uint8_t buffer[32768];
[self updateStatus:@"Receiving"];
// Pull some data off the network.
bytesRead = [self.networkStream read:buffer maxLength:sizeof(buffer)];
if (bytesRead == -1) {
[self stopReceiveWithStatus:@"Network read error"];
} else if (bytesRead == 0) {
[self stopReceiveWithStatus:nil];
} else {
NSInteger bytesWritten;
NSInteger bytesWrittenSoFar;
// Write to the file.
bytesWrittenSoFar = 0;
do {
bytesWritten = [self.fileStream write:&buffer[bytesWrittenSoFar] maxLength:(NSUInteger) (bytesRead - bytesWrittenSoFar)];
assert(bytesWritten != 0);
if (bytesWritten == -1) {
[self stopReceiveWithStatus:@"File write error"];
break;
} else {
bytesWrittenSoFar += bytesWritten;
}
} while (bytesWrittenSoFar != bytesRead);
}
} break;
case NSStreamEventHasSpaceAvailable: {
assert(NO); // should never happen for the output stream
} break;
case NSStreamEventErrorOccurred: {
[self stopReceiveWithStatus:@"Stream open error"];
} break;
case NSStreamEventEndEncountered: {
// ignore
} break;
default: {
assert(NO);
} break;
}
}
#pragma mark * UI Actions
- (void)GetDownloadStart
{
NSLog(@"download");
[self startReceive];
}
- (void)dealloc
{
[self stopReceiveWithStatus:@"Stopped"];
}
@end
Re: [objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月25日(水) 12:25
by h2so5
Re: [objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月25日(水) 14:04
by matunon
今回のソースでは、NSInputStreamを事前に作成し、このストリームに対してCFreadStreamWithFTPURLを設定しています。
ReadStreamRefに対してなら分かるのですがNSInputStreamは未知すぎて分かりません。
一応実験として
CFReadStreamSetProperty(self.networkStream, //NSinputStream
kCFStreamPropertyFTPUsePassiveMode,
kCFBooleanFalse);
を入力してみたのですがエラーが出てしまいました。(代入する値が違うというエラー)
NSInputStreamの中にReadStreamRefの値を入れる方法が存在するのでしょうか?
Re: [objective-c]FTP通信でのモード切り替えについて
Posted: 2014年6月25日(水) 15:21
by matunon
コード:
self.networkStream = CFBridgingRelease(CFReadStreamCreateWithFTPURL(NULL,
(__bridge CFURLRef)url));
CFReadStreamSetProperty(readStream, //ここでエラー
kCFStreamPropertyFTPUserName,
(CFTypeRef)@"splanet");
CFReadStreamSetProperty(readStream,
kCFStreamPropertyFTPPassword,
(CFTypeRef)@"spadmin2013$");
CFReadStreamSetProperty(readStream,
kCFStreamPropertyFTPUsePassiveMode,
kCFBooleanFalse);
self.networkStream = (__bridge NSInputStream *)readStream;
assert(self.networkStream != nil);
self.networkStream.delegate = self;
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.networkStream open];
このような感じにしてみたのですが、EXC_BAD_ACCESSエラーが表示されてしまいます。