【问题标题】:How to synchronize Read/Write to Stream?如何同步读/写到流?
【发布时间】:2010-08-19 20:24:45
【问题描述】:

您好, 我在 C# 中有自定义 Telnet 客户端。我正在使用它与 IMAP 服务器进行通信。它就像写命令一样工作,然后得到响应。测试代码:

            Telnet tc = new Telnet();
            // setup server credentials
            const string server = "pop.nexlink.net";
            const int port = 140;
            const int timeout = 70;
            // establish server connection
            tc.Setup(server, port, timeout);
            // test initial server response
            Console.WriteLine(tc.output);

            // set-up a few commands to send
            var array = new[] { "USER AppChecker@nexlink.net", "PASS password", "QUIT" };

            // while connected to server
            if (tc.IsConnected)
            {
                foreach (string str in array)
                {
                    // Show command on console
                    Console.WriteLine(str);
                    // Write to Stream
                    tc.WriteLine(str);
                    // Read from Stream
                    tc.Read();
                    // Test the Stream output
                    Console.Write(tc.output);
                }


            }
            // close connection
            tc.Disconnect();

调用上述代码的输出是:

  1. 用户 AppChecker@nexlink.net
  2. +OK 欢迎使用 Atmail POP3 服务器 - 使用 user@domain 登录。
  3. +OK 需要密码。
  4. PASS 密码
  5. 退出
  6. +OK 登录。
  7. +好的,再见。

这是一个简单的示例,但它显示了竞争条件的问题。第 nr.6 行的输出应出现在 nr 之前。 5

问:如何处理?

【问题讨论】:

  • 似乎做得很好。服务器在完成用户登录之前收到退出消息。
  • 有可能。反应相当随机。这取决于连接速度、服务器响应时间、要返回的数据量。一旦有更多的命令每个都请求更大的流,它就会变得非常混乱。一般来说,读取比写入慢得多。

标签: c# synchronization telnet


【解决方案1】:

首先,IMAP 邮件服务器不支持 Telnet。 Telnet 是 TCP 之上的协议。见RFC 854。然而,Telnet 客户端的优点在于,由于 Telnet 是原始 TCP 套接字之上的一个非常小的协议,因此您可以连接到许多服务并与之交互,这些服务也使用 TCP 之上的文本命令/响应样式协议(POP3、IMAP、 SMTP、HTTP 等)。

最终,您可能应该只使用“现成的 IMAP 客户端”。做一些随机的谷歌搜索把我带到this one。我不知道它是否好,但它可能会导致您快速获胜。

但是,如果您想学习如何正确地进行 TCP/IP 网络,您必须了解一些有关双向 IO 的基础知识。

您在这里遇到的情况很正常。 TCP 套接字上有两个通道。一种用于阅读,一种用于书写。这些通道是独立的并且可能被缓冲。

缓冲意味着仅仅因为您在客户端代码中向发送套接字写入了一些数据(一行或其他内容)并不意味着它已在另一端接收到。

因此,在写入后立即阻止读取可能意味着您的命令永远不会发送,您将永远阻止读取。

此外,您可以在操作系统和带宽允许的范围内尽可能快地将命令写入发送套接字。每当服务器开始处理回复时,回复就会返回。这可能很快,也可能永远不会。就其本质而言,套接字编程是异步的并且容易失败(毕竟您是在不可靠的网络上处理远程系统)。

处理异步双向 IO 的常用方法是拥有两个线程。一个用于阅读,另一个用于写作。当您必须协调两个线程之间的请求和响应的“聊天”时,“乐趣”就开始了。像 AutoResetEvent 和 ManualResetEvent 这样的线程原语可以在这里提供帮助。尽管您可能最好查看C# Reactive Extensions,因为它们可以使工作变得更简单。

总的来说,我建议reading up on the topic。即使对于 SMTP 和 POP3 等“简单”协议,编写良好的无错误网络代码也并非易事。

如果您不习惯使用 C# 作为您的解决方案,而您只是想自动化一些简单的 Telnet 样式服务交互,那么您应该查看 Linux/Unix 实用程序 expect,它可以为您节省大量时间.

【讨论】:

  • 谢谢,我一定会检查以上所有内容。
【解决方案2】:

我过去手动编写了自己的 telnet 客户端。我处理命令的方式是为每个命令编写一个流程,其中包含输入和预期的响应(我期望的部分回复,在你的情况下是 +OK)。这将允许我发送命令并等待响应。如果没有收到响应或者不匹配,则抛出异常。

Telnet 可以为每个命令发送许多响应(空白、页面更改、登录流程等)。所以等待您的预期响应是必要的。

【讨论】:

  • 这里行不通。该程序必须适用于许多服务器(我从事 ISP 业务)。欢迎使用更通用的解决方案。我正在考虑多线程和锁定资源,但不知道如何做到这一点。
  • 没有看到多服务器环境无法使用这种方法。请解释一下...您一次仍然只连接到一个 Telnet 实例。正确的?封装所有需要的命令后,我将 Telnet 外观公开为 WCF 服务并管理与 Telenet 服务器的连接池。
猜你喜欢
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
  • 2012-07-23
  • 1970-01-01
相关资源
最近更新 更多