如何在 TcpClient 类中使用 SSL

Posted

技术标签:

【中文标题】如何在 TcpClient 类中使用 SSL【英文标题】:How to use SSL in TcpClient class 【发布时间】:2012-01-12 14:02:54 【问题描述】:

在 .NET 框架中有一个类 TcpClient 用于从电子邮件服务器检索电子邮件。 TcpClient 类有 4 个构造函数来连接服务器,最多接受两个参数。它适用于那些不使用 SSL 的服务器。但是 gmail 或许多其他电子邮件提供商使用 SSL 进行 IMAP。

我可以连接 gmail 服务器,但无法使用 email_id 和密码进行身份验证。

我的验证用户代码是

public void AuthenticateUser(string username, string password)

    _imapSw.WriteLine("$ LOGIN " + username + " " + password);
    //_imapSw is a object of StreamWriter class
    _imapSw.Flush();
    Response();

但是这段代码无法登录。

那么当我必须使用 SSL 时,如何使用 TcpClient 类来检索电子邮件?

【问题讨论】:

【参考方案1】:

您可以用SslStream 包装TcpClient 提供的NetworkStream。这将提供对 SSL 和证书的必要处理。

您可能需要插入一些处理程序代码来执行证书验证回调,例如通过ServicePointManager.ServerCertificateValidationCallback

【讨论】:

【参考方案2】:

您必须使用SslStream 和TcpClient,然后使用 SslStream 而不是 TcpClient 来读取数据。

类似的东西:

        TcpClient mail = new TcpClient();
        SslStream sslStream;

        mail.Connect("pop.gmail.com", 995);
        sslStream = new SslStream(mail.GetStream());

        sslStream.AuthenticateAsClient("pop.gmail.com");

        byte[] buffer = new byte[2048];
        StringBuilder messageData = new StringBuilder();
        int bytes = -1;
        do
        
            bytes = sslStream.Read(buffer, 0, buffer.Length);

            Decoder decoder = Encoding.UTF8.GetDecoder();
            char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
            decoder.GetChars(buffer, 0, bytes, chars, 0);
            messageData.Append(chars);

            if (messageData.ToString().IndexOf("<EOF>") != -1)
            
                break;
            
         while (bytes != 0);

        Console.Write(messageData.ToString());
        Console.ReadKey();

编辑

上面的代码将简单地通过 SSL 连接到 Gmail 并输出测试邮件的内容。要登录 gmail 帐户并发出命令,您需要执行以下操作:

        TcpClient mail = new TcpClient();
        SslStream sslStream;
        int bytes = -1;

        mail.Connect("pop.gmail.com", 995);
        sslStream = new SslStream(mail.GetStream());

        sslStream.AuthenticateAsClient("pop.gmail.com");

        byte[] buffer = new byte[2048];
        // Read the stream to make sure we are connected
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

        //Send the users login details
        sslStream.Write(Encoding.ASCII.GetBytes("USER USER_EMAIL\r\n"));
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

        //Send the password                        
        sslStream.Write(Encoding.ASCII.GetBytes("PASS USER_PASSWORD\r\n"));
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

        // Get the first email 
        sslStream.Write(Encoding.ASCII.GetBytes("RETR 1\r\n"));
        bytes = sslStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

显然,没有所有重复的代码:)

【讨论】:

谢谢您的回答。但用户登录是我的主要问题。 非常感谢您的回答。我工作得很好。在某种程度上它使用 pop 协议来访问邮件。但我想使用 imap 协议访问电子邮件。我已将邮件服务器名称和端口号更改为“imap.gmail.com”和“993”,但它不起作用。怎么做? 如果您是“服务器”而不是客户端,这将如何改变?我想使用 ssl 接收连接? 我在循环的第二次迭代中冻结了 bytes = sslStream.Read(buffer, 0, buffer.Length) 因为 messageData.ToString() 没有 【参考方案3】:

要针对 IMAP 和 IMAP 身份验证问题定制上述最佳响应,您需要稍微修改代码以使用 IMAP 命令,如下所示。对于调试,您可以在分配 strOut 后设置断点以查看服务器响应。

            pmOffice pmO = new pmOffice();
            pmO.GetpmOffice(3, false);

            TcpClient mail = new TcpClient();
            SslStream sslStream;
            int bytes = -1;

            mail.Connect("outlook.office365.com", 993);
            sslStream = new SslStream(mail.GetStream());

            sslStream.AuthenticateAsClient("outlook.office365.com");

            byte[] buffer = new byte[2048];
            // Read the stream to make sure we are connected
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));

            //Send the users login details (insert your username & password in the following line
            sslStream.Write(Encoding.ASCII.GetBytes("$ LOGIN " + pmO.mailUsername + " " + pmO.mailPassword + "\r\n"));
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            string strOut = Encoding.ASCII.GetString(buffer, 0, bytes);

            // Get the status of the inbox (# of messages)
            sslStream.Write(Encoding.ASCII.GetBytes("$ STATUS INBOX (messages)\r\n"));
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            strOut = Encoding.ASCII.GetString(buffer, 0, bytes);

【讨论】:

什么是 pmOffice? pmOffice 是我创建的一个类,用于从数据库访问我的邮件设置和凭据。

以上是关于如何在 TcpClient 类中使用 SSL的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 TcpClient 连接是不是关闭?

TcpClient 是单个连接使用吗?如何发送第二条消息?

如何正确使用 TcpClient ReadTimeout

如何设置 TcpClient 的超时时间?

网络编程中,使用Socket和TcpClient有啥区别

C# - 执行 SslStream.Read 后如何知道 TcpClient 中剩余多少字节