【问题标题】:How to keep async system.net.socket listener alive in windows application如何在 Windows 应用程序中保持异步 system.net.socket 侦听器处于活动状态
【发布时间】:2015-04-18 13:01:53
【问题描述】:

我正在使用多线程 system.net.socket 来监听单个端口。我想捕获来自多个客户端的同时请求。这是我的示例:

private static ManualResetEvent _manualResetEvent = new ManualResetEvent(false);

public class Program
{
    static void Main(string[] args)
    {
        Program program = new Program();
        Thread threadListener = new Thread(program.StartListening);
        threadListener.Start();
    }

    private void StartListening()
    {
         IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt32(ConfigurationManager.AppSettings["httpPort"].ToString()));

         Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

         listener.Blocking = false;
         listener.Bind(localEndPoint);
         listener.Listen(10);

         listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
    }

    public static void AcceptCallback(IAsyncResult ar)
    {
         _manualResetEvent.Set();

         Socket listener = (Socket)ar.AsyncState;

         Socket handler = listener.EndAccept(ar);

         StateObject state = new StateObject();
         state.workSocket = handler;

         handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);

         listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
    }

    private void ReceiveCallback(IAsyncResult result)
    {
        StateObject state = null;
        Socket handler = null;

        try
        {
            state = (StateObject)result.AsyncState;
            handler = state.workSocket;

            int numBytesReceived = handler.EndReceive(result);

            if (!handler.Connected)
            {
                handler.Close();
                return;
            }

            if (numBytesReceived > 0)
            {
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, numBytesReceived));

                string[] lines = state.sb.ToString().Split('\n');

                if (lines[lines.Length-1] == "EOF")
                {
                    // Do something according to client request
                }
                else
                {
                    // We didn't receive all data. Continue receiving...
                    handler.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
                }
            }
        }
        catch (ObjectDisposedException ex)
        {
            // Don't care
        }
        catch (Exception ex)
        {                
            if (handler != null)
            {
                handler.Close();
            }
        }
    }
}

public class StateObject
{
    public Socket workSocket = null;
    public const int BufferSize = 256;
    public byte[] buffer = new byte[BufferSize];
    public StringBuilder sb = new StringBuilder();
}

问题是我无法仅使用这些代码来保持应用程序运行。如果我运行此应用程序并捕获客户端请求,我的 ReceiveCallBack 方法将正常工作,并且应用程序在成功执行后停止。

我可以使用这个MSDN link 中的示例代码来保持我的应用程序存活。它在 StartListening 方法中使用了一个 while 循环,如下所示:

while (true) 
{
     allDone.Reset();
     listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
     allDone.WaitOne();
}

但似乎 MSDN 为阻塞侦听器设计了此代码。我的意思是它不允许同时连接。所以不适合我。

在 MSDN 示例中,如果没有 while 循环,我必须防止我的应用程序在执行我的代码后停止。我必须保持它运行并持续监听多个同时连接。

那么我怎样才能保持该应用程序运行呢?

谢谢

【问题讨论】:

  • 您看到了什么异常消息?发布它和堆栈跟踪。
  • @Yuval 感谢您的关注,看来我今天用错误的词来定义我的问题。我会在 30 分钟后回来。你可以看到我编辑的问题。谢谢。
  • @OrkunBekar 我在您发布的代码中没有看到任何会停止应用程序的内容。这段代码将永远接受客户,所以问题不在于那部分。如果应用程序因其他原因停止,则需要查看该代码。并且 MSDN 代码不是为阻塞侦听器设计的,它允许任意数量的连接。它只接受第一个,然后你再次BeginAccept
  • @OrkunBekar 在这种情况下,您甚至根本不需要异步。您可以在循环中接受,然后调用 BeginReceive 以从那时起异步处理它。
  • @OrkunBekar 您接受连接,将接收设置为异步,接受另一个,异步接收等等。然后,您将同时处理所有连接。无论如何,您不能同时处理接受连接,它们总是顺序的。这是关于将异步并同时运行的实际数据传输。

标签: c# .net multithreading sockets


【解决方案1】:

问题是没有线程可以使您的进程保持活动状态。很短的时间后,只有线程池线程存在并且运行时关闭。

从 Main 开始一个新线程什么也没做。告诉我你认为这应该实现什么,我会消除误解。主要应该看起来像StartListening(); Thread.Sleep(Timeout.Infinite);。 (反直觉!)

除此之外,代码虽然质量低,但仍然可以使用。问题太多,我就不详细评论了。将此提交给 Codereview SE。

【讨论】:

  • 如果我使用 Application.Run() 而不是 Thread.Sleep(Timeout.Infinite) 会有什么不同吗?
  • 那也不错。请注意,只要 Run 调用退出,进程就会关闭。关键是不要让线程死掉。你放什么都没关系。
  • 我可以在线程退出事件等中保存应用程序吗?我该如何处理?如果它进入 threadexit 事件,那么我想一切都结束了?
  • 这不是正确的方法。如果您可以简单地确定性地保持应用程序的运行,为什么还要做出反应?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多