不确定我是否在tftp app中正确使用“使用”c#

时间:2014-07-31 23:14:02

标签: c# winforms tftp

我尝试在我的windows c#表单中使用this预先制作的C#tftp服务器应用程序。在作者服务器示例中,它运行良好,他使用控制台应用程序。当我尝试将他的控制台示例移植到我的表单应用程序时,它不起作用(没有错误,只是没有连接),我相信我的问题在"使用"语句:

using (var server = new TftpServer())
{
    server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
    server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
    server.Start();
    Console.Read();
}

不确定我是否理解正确,但我相信Console.Read()会阻止应用退出。如果是这种情况,我将如何使用表单应用程序实现等效项。我无法绕过"使用"。对不起,我是c#的新手。

4 个答案:

答案 0 :(得分:5)

Windows窗体将始终保持打开状态,直到用户明确关闭它们为止。它们总是有一个线程读取消息队列以供用户输入,因此它们不会以无限制的控制台应用程序的相同方式退出。在Windows窗体中,我们不得不担心多线程和并发性,而不是在控制台应用程序中。它主要是自然而然的,但并非总是如此。

正因为如此,在用户请求之前,您无法真正使用等同于Console.Read()来暂停执行using处理。如果你这样做了,你的表单就会显得没有反应。

但是,你很幸运! C#中的using块只不过是用于记住在完成对象后调用IDisposable.Dispose()的语法糖。因此,在Forms项目中与此类似,只需将server对象存储在类范围的字段中,然后调用server.Dispose(),例如,Button.Click事件。当然,这只是一个例子。如果感觉更合适,您也可以在Form.Closing上执行此操作。

高级别,你想做这样的事情:

  1. 在表单类TftpServer server;中声明一个字段。
  2. 注册Load事件以及server在构造函数中运行所需的任何内容。
  3. server活动中打开Form_Load字段。
  4. server的生命周期内使用您认为合适的Form个活动。您可能会或可能不必担心并发性,但这是另一个问题的问题。
  5. 在表格server.Dispose()活动中致电Dispose
  6. 实质上,

    class main : Form
    {
        private TftpServer server;
    
        public main()
        {
            InitializeComponent();
    
            this.Load += main_Load;
    
            server = new TftpServer();
            server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
            server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
        }
    
        private void main_Load(object sender, EventArgs e)
        {
            server.Start();
        }
    
        private void server_OnReadRequest(/* I wasn't sure of the arguments here */)
        {
            // use the read request: give or fetch its data (depending on who defines "read")
        }
        private void server_OnWriteRequest(/* I wasn't sure of the arguments here */)
        {
            // use the write request: give or fetch its data (depending on who defines "write")
        }
    
        protected override void Dispose(bool disposing)
        {
            if (server != null) // since Dispose can be called multiple times
            {
                server.Dispose();
                server = null;
            }
        }
    }
    

答案 1 :(得分:3)

问题在于处理服务器正在关闭它。请记住,使用只是语法糖。以下两个代码块实际上是等价的:

var foo = new Foo();
try
{
   foo.Do();
}
finally
{
   foo.Dispose();
}

using (var foo = new Foo())
{
   foo.Do();
}

你可以很好地阻止主线程在控制台应用程序中退出,但在Forms应用程序中它是不同的。问题不在于您需要通过执行某种阻塞操作来保持线程在使用中。这将是不好的,行为将锁定您的表单应用程序。问题是你不想使用。您希望在启动服务器时启动它,然后在应用程序退出时或在停止单击时使用Dispose()显式处理它。

答案 2 :(得分:1)

在控制台应用程序中,您的TftpServer实例正在侦听,直到线程退出时才会按下Console.Read()

检测到的某个键。

Console.Read()不等待的表单应用中,using块结束,导致您的服务器实例超出范围。

所以你并没有完全滥用using,而是预期用途根本没有帮助你。看一下使用task parallel library让一些后台任务异步运行。

答案 3 :(得分:1)

一个小注释也可以作为答案,你可以在这里使用一个使用块,你只需将它放在你的主函数中:

...(make your form and stuff) 
using (var server = new TftpServer())
{
   server.OnReadRequest += new TftpServerEventHandler(server_OnReadRequest);
   server.OnWriteRequest += new TftpServerEventHandler(server_OnWriteRequest);
   server.Start();
   Application.Run(yourFormHere); //This blocks until the form is closed
}

我忘记提及的另一个选项是在表单中覆盖Dispose。你可能想要这样做。使用此选项,您可以保证您的服务器将被处理掉(禁止某些事件阻止它以任何方式处置[即内存不足])