0

filename(string)、filesize(int)、およびfile(byte [])を送信しています。何が起こっているのかというと、サーバー側でデータが処理される速度に応じて、NetworkStreamがまだ必要のないデータを読み取った場合があります。

例:.Readを実行してファイル名を取得し、filename、filesize、およびファイルの生データのデータを取得します。これは、最初の.Readがまだ実行されていないときに、サーバーが.Writeを実行し、データをストリームに書き込むために発生すると思います。これは私のファイルサイズを壊してしまいます。ファイルサイズの.Readを実行すると、巨大な数値が表示され、ファイル自体を読み取り、読み取ったファイルサイズに基づいて新しいbyte []を割り当てると、OutOfMemory例外が発生します。

読み取りを正しく同期するにはどうすればよいですか?私がネット上で見つけた例は、私と同じようにそれを行っています。

いくつかのコード:

   private void ReadandSaveFileFromServer(TcpClient clientATF, NetworkStream currentStream, string locationToSave)
    {
        int fileSize = 0;
        string fileName = "";
        int readPos = 0;
        int bytesRead = -1;

        fileName = ReadStringFromServer(clientATF, currentStream);

        fileSize = ReadIntFromServer(clientATF, currentStream);


        byte[] fileSent = new byte[fileSize];

        while (bytesRead != 0)
        {
            if (currentStream.CanRead && clientATF.Connected)
            {

                bytesRead = currentStream.Read(fileSent, readPos, fileSent.Length);

                readPos += bytesRead;
                if (readPos == bytesRead)
                {
                    break;
                 }

            }
            else
            {
                WriteToConsole("Log Transfer Failed");
                break;
            }
        }
        WriteToConsole("Log Recieved");

        File.WriteAllBytes(locationToSave + "\\" + fileName, fileSent);


    }


 private string ReadStringFromServer(TcpClient clientATF, NetworkStream currentStream)
    {
        int i = -1;
        string builtString = "";
        byte[] stringFromClient = new byte[256];



            if (clientATF.Connected && currentStream.CanRead)
            {

                i = currentStream.Read(stringFromClient, 0, stringFromClient.Length);
                builtString = System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i);

            }

            else
            {
                return "Connection Error";
            }



        return builtString;

    }

    private int ReadIntFromServer(TcpClient clientATF, NetworkStream currentStream)
    {
        int i = -1 ;
        int builtInteger = 0;
        byte[] integerFromClient = new byte[256];
        int offset = 0;


            if (clientATF.Connected && currentStream.CanRead)
            {

                i = currentStream.Read(integerFromClient, offset, integerFromClient.Length);

                builtInteger = BitConverter.ToInt32(integerFromClient, 0);

            }

            else
            {
                return -1;
            }



        return builtInteger;
    }

私はオフセットを使用してみました... あなたの助けに感謝します。

私は別の質問を始めましたが、それは何か他のものに関連しています。

よろしくお願いしますショーン

編集:これが私の送信文字列コードです:

  private void SendToClient( TcpClient clientATF,  NetworkStream currentStream, string messageToSend)
    {
        byte[] messageAsByteArray = new byte[256];

        messageAsByteArray = Encoding.ASCII.GetBytes(messageToSend);

        if (clientATF.Connected && currentStream.CanWrite)
        {
            //send the string to the client

                currentStream.Write(messageAsByteArray, 0, messageAsByteArray.Length);

        }

    }
4

4 に答える 4

1

TCP / IPはデータグラムではなくストリーミングであるため、必要な動作はそこにありません。ストリームに解析するのに十分な情報を含めることで、この問題を回避できます。

つまり、テキスト行の後にCR / LFなどの区切り文字を使用したり、次のデータの長さを指定したりできます。必要に応じて、固定サイズのフィールドを使用することもできます。

于 2010-09-20T21:08:15.047 に答える
1

一度にストリームから読み取られるバイト数に依存することはできません。ReadStringFromServer文字列が固定長(256)であると仮定すると、メソッドにバグがあります。

それ以外の:

 i = currentStream.Read(stringFromClient, 0, stringFromClient.Length);
 builtString = System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i);

試す:

 do
 {
    i = currentStream.Read(stringFromClient, 0, 256 - builtString.Length);
    builtString+=(System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i));
 } while(builtString.Length < 256)
于 2010-09-20T21:19:23.020 に答える
1

より良い解決策は、おそらくすべてのデータを(たとえば、JSONに)シリアル化し、すべてをネットワークストリームに渡すことです。

于 2010-09-20T21:22:14.933 に答える
1

Read()を呼び出す方法では、256バイトがプルされます。これが、stringFromClient.Lengthが設定されたものです。

データのストリームを正確に切り刻むには2つのオプションがあり、どちらもデータ間の境界を把握または把握する方法を作成する必要があります。それらは、区切られたストリームと固定長のストリームです。

区切り形式の場合、ファイル名またはサイズの有効な部分として使用しない文字(パイプ、スペース、タブ文字、改行など)を選択し、ファイル名とサイズの間、および間に1つ挿入します。サイズとファイルの内容。次に、区切り文字に到達するまで、一度に1バイトずつ配列に読み込みます。区切り文字を除いてこれまでに読み取ったバイトはデータです。使用可能なフォームに抽出して返します。これにより、通常、ストリームが短くなりますが、使用されない可能性のある文字が1つ必要です。

固定サイズのフォーマットの場合、データの妥当な値が超えないバイト数を決定します。たとえば、ファイル名は256文字を超えることはできません(おそらく約50文字を超えることはできません。一部の古い/単純なOSでも8に制限されています)。どのWindows環境でもファイルサイズは2^64バイトを超えることはできず、その数は4バイトの生の数値データまたは20文字の文字列で表すことができます。したがって、どの制限を選択しても、適切なバッファを使用してデータをパディングします。生の数値の場合はInt64にキャストしてバイトに切り刻み、文字列の場合はスペースを埋め込みます。次に、最初のXバイトが正確にファイル名になり、次のYバイトが正確にファイルサイズになり、それ以降はコンテンツになります。これによりストリームが大きくなりますが、特別なバイト値や予約済みのバイト値がないため、内容は何でもかまいません。

于 2010-09-20T21:24:42.773 に答える