繁体   English   中英

在WinForms应用程序中关闭套接字服务器的正确方法?

[英]Proper way to shut down socket server in WinForms application?

我正在使用C#中的基本套接字服务器进行工作,该服务器需要作为Windows Forms应用程序的一部分运行。 我从MSDN的异步套接字服务器代码开始。 像许多套接字服务器代码示例一样,这是一个控制台模式应用程序。 这是从Main()调用的StartListening()方法的示例:

public static void StartListening()
{
    // data buffer for incoming data
    byte[] bytes = new byte[1024];

    IPAddress ipAddress = IPAddress.Parse(serverIpAddress);
    IPEndPoint localEndPoint = new IPEndPoint(ipAddress, portNumber);

    // create TCP/IP socket
    Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    // bind socket to the local endpoint and listen for incoming connections
    try
    {
        serverSocket.Bind(localEndPoint);
        serverSocket.Listen(100);

        while (true)
        {
            // set the allDone ManualResetEvent to nonsignaled state
            allDone.Reset();

            // start an asynchronous socket to listen for connections
            Console.WriteLine("Waiting for a connection...");
            serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);

            // wait until a connection is made before continuing
            allDone.WaitOne();
        }

    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }

    Console.WriteLine("\nPress ENTER to continue...");
    Console.Read();
}

如您所见,其中有一个while(true)循环,该循环使用ManualResetEvent等待进入客户端连接,然后进入While循环的下一个迭代。 我不确定为什么它们包含Console.WriteLine(\\n"Press ENTER to continue...")语句,因为没有办法打破while(true)循环。

无论如何,在考虑将其转换为WinForms应用程序时,我显然需要在另一个线程上运行服务器,但是当用户关闭我的应用程序时,我要确保套接字服务器“正确”关闭。 我的最佳猜测是关闭任何打开的客户端连接,中断侦听循环,然后关闭服务器套接字(不一定按此顺序)。

我已经看到一些建议,这些建议只建议使服务器线程成为后台线程,并在应用程序关闭时让它被销毁,但这似乎不太“干净”。 例如,如果关闭了客户端的连接并在应用程序关闭时发送数据,那么这对客户端有什么作用? 任何人都可以建议有关正确关闭套接字服务器的“最佳实践”吗?

我会将整个内容包装在Task中,并使用取消标记。

有关使用任务和取消令牌的良好示例,请参阅https://msdn.microsoft.com/zh-cn/library/hh160373(v=vs.110).aspx 当您要关闭套接字服务器时,可以使取消令牌取消任务。

在任务内部会引发异常。 在异常处理程序中,您调用Socket.Close,这将停止BeginAccept调用(将调用EndAccept,但Socket.Handle将为-1)。

实际上,您不需要线程,因为您已经在异步监听。

只需在AcceptCallback的结尾再次调用serverSocket.BeginAccept 然后,服务器的关闭将减少为serverSocket.Close() (显然, serverSocket必须是一个类字段)。

最后,在AcceptCallback您需要捕获EndAccept的异常。 顺便说一句,这就是为什么在示例中出现Console.WritelineConsole.Readkey的原因:当发生异常时执行。

  1. 此块:Console.WriteLine(“ \\ n按ENTER继续...”); Console.Read(); 那里是因为编写此方法的方式,如果引发异常,它将退出循环。

  2. 我会这样写以适合您的参数:

     using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { private Socket serverSocket; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { StartListening(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { serverSocket.Close(); } public void StartListening() { byte[] bytes = new byte[1024]; IPAddress ipAddress = IPAddress.Parse(serverIpAddress); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, portNumber); serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { serverSocket.Bind(localEndPoint); serverSocket.Listen(100); while(true) { allDone.Reset(); Console.WriteLine("Waiting for a connection..."); serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket); // wait until a connection is made before continuing allDone.WaitOne(); } } catch(Exception e) { Console.WriteLine(e.ToString()); } finally { serverSocket.Close(); } Console.WriteLine("\\nPress ENTER to continue..."); Console.Read(); } } } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM