2

C#とMicrosoft .Net CompactFramework1.0を使用しています。System.Net.Sockets.NetworkStreamTcpClientクラスを使用してPOP3プロトコルを実装しようとしました。ログインして電子メールを受信し、いくつかの電子メールサーバーで添付ファイルを保存することができます。しかし、一部の人にとっては、私は問題にぶつかり続けます。

List <Index>コマンドを送信してメールメッセージのサイズを読み取りました。状況によっては、実際の値よりも大幅に小さいサイズになります。たとえば、同じEメールの場合:

Actual size: 577860, Returned size: 421096 using Exchange 2007
Actual size: 561005, Returned size: 560997 using Exchange 2003

なぜ私は今までに正しいサイズを手に入れないのですか?私が使用している次のコード。

電子メールのサイズは、手順StringBuilderの最後ののサイズと一致することはありません。PopRead電子メールのサイズが信頼できず、読み取ることができるデータがさらにある場合でも、のDataAvailableプロパティがNetworkStream誤っていることがあるため、電子メールを確実に読み取ることができません。

DataAvailableActiveSyncを介してコンピューターのインターネット接続を使用する場合よりも、(データプランを使用して)無線で電子メールサーバーに接続しようとすると、プロパティがfalseになることがよくあります。

それが役立つ場合、電子メールサーバーはExchange2003とExchange2007です。

private bool POPRead(StringBuilder strBuffer, long lngFetchMailSize)
{
   const int bufferSize = 1024;

    byte[] inb;
    if (enc == null)
    {
        enc = new ASCIIEncoding();
    }

    try
    {
        if (lngFetchMailSize > 0 && lngFetchMailSize < (32 * bufferSize))
        {
            // limit the size of the buffer as the amount of memory
            // on Pocket PC is limited.
            inb = new byte[lngFetchMailSize];
        }
        else
        {
            inb = new byte[bufferSize];
        }
        Array.Clear(inb, 0, inb.Length);
        bool bMoreData = true;
        long iBytesRead = 0L;
        int bytesReadInThisRound = 0;

        int numberOfTimesZeroBytesRead = 0;

        while (bMoreData)
        {
            bytesReadInThisRound = this.nsPOP.Read(inb, 0, inb.Length);
            iBytesRead += bytesReadInThisRound;

            if (bytesReadInThisRound == 0)
            {
                numberOfTimesZeroBytesRead++;
            }
            else
            {//If on a retry the data read is not empty, reset the counter.
                numberOfTimesZeroBytesRead = 0;
            }

            strBuffer.Append(enc.GetString(inb, 0, bytesReadInThisRound));
            Array.Clear(inb, 0, bytesReadInThisRound);
            // DataAvailable sometimes gives false even though there is
            // more to be read.
            bMoreData = this.nsPOP.DataAvailable;
            // Use this number (5), since some servers sometimes give the size
            // of the email bigger than the actual size.
            if ((lngFetchMailSize != 0 && !bMoreData)
                && (iBytesRead < lngFetchMailSize)
                && numberOfTimesZeroBytesRead < 5)
            {
                bMoreData = true;
            }
        }
    }
    catch (Exception ex)
    {
        string errmessage = "Reading email Expected Size: " + lngFetchMailSize;
        LogException.LogError(ex, errmessage, false, "oePPop.POPRead");
        Error = ex.Message + " " + errmessage;
        return false;
    }
    finally
    {
        GC.Collect();
    }
    return true;
}

次の手順を使用して、電子メールメッセージのサイズを取得します。

private long GetMailSize(int index)
{
    StringBuilder strBuffer = new StringBuilder();
    const string LISTError = "Unable to read server's reply for LIST command";
    if ((this.POPServer != null) && (this.nsPOP != null))
    {
        if (!this.POPWrite("LIST " + index))
        {
            return -1L;
        }
        if (!this.POPRead(strBuffer))
        {
            this.Error = LISTError;
            return -1L;
        }
        if (!this.IsOK(strBuffer))
        {
            return -1L;
        }
        string strReturned = strBuffer.ToString();
        int pos1 = strReturned.IndexOf(" ", 3);
        if (pos1 == -1)
        {
            this.Error = LISTError;
            return -1L;
        }
        int pos2 = strReturned.IndexOf(" ", (int)(pos1 + 1));
        if (pos2 == -1)
        {
            this.Error = LISTError;
            return -1L;
        }
        int pos3 = strReturned.IndexOf("\r\n", (int)(pos2 + 1));
        if (pos3 == -1)
        {
            this.Error = LISTError;
            return -1L;
        }
        long mailSize = 0;
        Int64.TryParse(strBuffer.ToString(pos2 + 1, pos3 - (pos2 + 1)).Trim(), out mailSize);
        return mailSize;
    }
    this.Error = NotConnectedError;
    return -1L;
}

問題を解決するために必要なすべての情報を提供したことを願っています。正しい方向へのヘルプやポインタは、多くの助けになります。

ありがとう、
チャンドラ。

4

3 に答える 3

1

あなたのエラーは、ASCIIEncoder をそのまま使用している可能性があります。

MSDNから:

ストリームから読み取られたデータなど、変換されるデータは、順次ブロックでのみ使用できます。この場合、またはデータ量が大きすぎて小さなブロックに分割する必要がある場合、アプリケーションは、GetDecoder メソッドまたは GetEncoder メソッドによってそれぞれ提供される Decoder または Encoder を使用する必要があります。

一度に少しずつデコードしているため、ストリームの一部を正しくデコードしていない可能性があります。

デコーダーを使用するようにコードを変更するか、一度にメッセージ全体を読み取ってから GetString() メンバーでデコードします。

追加のサニティ チェックとして、RETR <index> が返すメッセージ サイズを使用して、LIST が返すものと一致するかどうかを確認できます。それらが一致しない場合、少なくとも私は RETR が返すものを使用します。

于 2009-04-18T01:54:47.073 に答える
0

POP3はトリッキーなプロトコルです。扱うべき非常に多くの異なるサーバー、多くは独自のあいまいな癖を持っています。これが本番アプリの場合、徹底的にテストされたサードパーティのコンポーネントを購入することを真剣に検討します。

于 2009-04-17T23:38:18.367 に答える
0

電子メールはピリオドで終了する必要があるため、ループの終了のためにこの比較を行います。

それ以外の

 if ((lngFetchMailSize != 0 && !bMoreData)
       && (iBytesRead < lngFetchMailSize)
       && numberOfTimesZeroBytesRead < 5)
  {
      bMoreData = true;
  }

私はそれを次のように書きます

  if(!bMoreData 
    && strBuffer.ToString(strBuffer.Length - 5, 5) != "\r\n.\r\n")
  {
       bMoreData = true;
  }
于 2009-04-21T02:04:10.800 に答える