2

我正在使用 C# 和 Microsoft .Net Compact Framework 1.0。我尝试使用System.Net.Sockets.NetworkStreamandTcpClient类来实现 POP3 协议。我能够登录并接收电子邮件并使用一些电子邮件服务器保存附件。但对于某些人来说,我一直遇到问题。

List <Index>我通过发送命令来读取电子邮件的大小。在某些情况下,我得到的尺寸明显小于实际值。例如,对于同一个电子邮件:

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

为什么我总是找不到合适的尺寸?以下是我正在使用的代码。

电子邮件的大小永远不会与程序StringBuilder结束时的大小相匹配PopRead。我无法可靠地阅读电子邮件,因为电子邮件大小不可靠,并且DataAvailable属性NetworkStream有时是错误的,即使有更多数据可以读取。

我观察到,DataAvailable当我尝试通过无线方式(使用数据计划)连接到电子邮件服务器时,与通过 activesync 使用计算机的 Internet 连接时相比,该属性更常见。

如果有帮助,电子邮件服务器是 Exchange 2003 和 Exchange 2007。

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 是一个棘手的协议。有这么多不同的服务器要处理,许多都有自己晦涩难懂的怪癖。如果这是一个生产应用程序,我会认真考虑购买经过彻底测试的第 3 方组件。

于 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 回答