0

これは私を殺すつもりです。この1つのばかげた問題を除いて、私はこれを成し遂げるのにとても近いです。そして、問題を適切に説明できるかどうかはわかりませんが、試してみます。

私のエンタープライズアプリは、iPhoneカメラを使用して、現場担当者が購入した領収書の写真を撮ります。jpegデータをbase64(https://github.com/nicklockwood/Base64)に変換するために本当にクールなAPIを使用して、TCP接続を介してVB 2010サーバーに送信しました。VB2010サーバーは、データをテキスト文字列として読み取り、に変換し直します。バイナリ。

base64ファイルが作成されると、さらに多くの画像が存在する可能性があるため、最初に電話のディスクに保存されます。次に、送信の準備ができると、プロセスは各base64ファイルを読み取り、一度に1つずつ送信します。

base64関数によって作成されたテキスト文字列は非常に大きく、最初は約131,000バイトしか送信していませんでした。これは、簡単にバイナリに変換し直しますが、画像の約1 / 4〜1/3をレンダリングします。アプリがそれ自体を先取りしようとしていたため、データが切り捨てられていることがわかりました。

そこで、NSStreamEventHasSpaceAvailableイベントを使用してbase64文字列をいくつかのチャンクに分割し、それらを順番に送信する方法を示すスニペットを見つけました。(http://www.ios-developer.net/iphone-ipad-programmer/development/tcpip/tcp-client)これは、完全なファイルを送信する限り、つまり、サーバーが受信した結果のファイルが正しいサイズ。送信前のbase64ファイルと同じです。

ここでの問題は、サーバーが受信したファイルが、ファイルの先頭から最初からやり直しているように見えるために破損していることです。つまり、データが繰り返され始めます。

奇妙な部分は、繰り返し部分が毎回受信ファイルのまったく同じ場所、つまり位置131016から始まることです。ファイルの最後で繰り返しを開始するのではなく、その時点でファイルを中断してジャンプして戻ります。最初に。そして、それがHasSpaceAvailableイベントの使用を開始する前に送信されたファイルのサイズであったことが起こります。131,016という値の意味がわかりません。どこかの最大バッファサイズ?

あらゆる種類のNSLogとブレークポイントを使用して、データがそのように電話を離れ、サーバーによってスクランブルされていないことをほぼ確認しました。また、base64ファイルを添付ファイルとして電子メールで送信するNSMailComposeViewerメソッドを記述しましたが、これは完全に実行されます。

ファイルがディスクから読み取られてサーバーに送信されるときのコードは次のとおりです。

    int i;
    for (i = 0; i < [imageList count];i++){
    NSArray *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory= [documentsPath objectAtIndex:0]; //Get the docs directory
    NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:imageFileName];
    imageFileName = [imageList objectAtIndex:i] ;
    NSLog(@"Image index: %d - image file name: %@",i,imageFileName);

    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:imagePath];
    if(fileExists == YES){
        NSString *imageReceipt = [NSString stringWithContentsOfFile:imagePath encoding:NSASCIIStringEncoding error:nil];
        int32_t imageStringLen = [imageReceipt length];
        NSString *imageSize = [NSString stringWithFormat: @"%d",imageStringLen];
        NSString *currentImage = [NSString stringWithFormat:@"image,%@,%@,%@",imageFileName,imageSize,imageReceipt]; //creates a CSV string with a header string with the filename and file size, and then appends the image data as the final comma-separated string.
        data = [[NSMutableData alloc] initWithData:[currentImage dataUsingEncoding:NSASCIIStringEncoding]];

        [outputStream write:[data bytes] maxLength:[data length]];

そして、HasSpaceAvailableイベントを使用するコードは次のとおりです。

        case NSStreamEventHasSpaceAvailable:
        if (data != nil)
        {
            //Send rest of the packet
            int ActualOutputBytes = [outputStream write:[data bytes] maxLength:[data length]];
            int totalLength = [data length];

            if (ActualOutputBytes >= totalLength)
            {
                //It was all sent
                data = nil;

            }
            else
            {
                //Only partially sent
                [data replaceBytesInRange:NSMakeRange(0, ActualOutputBytes) withBytes:NULL length:0];       //Remove sent bytes from the start
            }
        }

        break;

(ProgressViewコントロールを画面に配置できるため、このコードが特に気に入っています。)

ネットワークストリームイベントハンドラーコードはルートビューコントローラーにありますが、base64のイメージデータは別のビューコントローラーから送信されています。私の本能は、これまでは問題なく機能していたので、これは問題ではないが、文字列がはるかに短いことを教えてくれます。

さて、関連しているかもしれないもう一つの問題があります-そしておそらくそうです。アプリを閉じないとデータの転送が完了しないようです。接続が閉じられるまで、サーバーはそれを認識しません。コード内のさまざまな場所に[outputStreamclose]を配置してみましたが無駄になりました。また、改行またはキャリッジリターン、あるいはその両方を使用してbase64文字列を終了しようとしました。

サーバーは、正しいバイト数を確認したときにファイルを保存するようにプログラムされていますが、アプリが閉じられるまでそれは発生しません。サーバーでWireSharkを使用することで、一部のデータが受信されていることがわかりますが、残りのデータは、私が言ったように、アプリが閉じられるまで到着しません。

この最後の部分(転送の完了)が問題だと思いますが、私がどの検索用語を使用するかを知らない限り、これに対処するものをオンラインで見つけることはできません。これは可能性が高いです。

十分な情報を提供できたと思います。誰か助けてもらえますか?

4

1 に答える 1

1

編集

問題の解決策は、元の回答で疑われていたものとは異なるように見えました。コメントでの議論を通じて、QPは解決策に導かれました。要約は次のとおりです。

生のTCPソケットを介したデータの送信には、QPによって適切に考慮されなかった、クエリロジックの完全な処理が必要です。CocoaAsyncSocketタスクのこの部分を処理し、QPを実用的なソリューションに導いたソケットライブラリを使用することをお勧めします。

元の回答:

私はNSStringその仕事に任されていないと思います。それは、まあ、ひもを保持するために作られています。

NSData代わりに、ファイルを直接読み込んで、バイナリとして送信してみてください。(最終的にはASCIIですよね?)さらに、これは現在のコードよりもはるかにリソースに優しいでしょう。

于 2013-02-18T22:10:10.587 に答える