【问题标题】:C# TCPListener keep listening after application shutdown only for the first timeC# TCPListener 仅在第一次关闭应用程序后继续侦听
【发布时间】:2019-01-02 01:18:33
【问题描述】:

我的申请有问题, 我有一个 TCPListener,比如说在端口 14000 上监听 关闭应用程序后,我可以在 CMD 上看到侦听器仍在侦听。 在应用程序的第二次运行时,我无法在同一个端口(14000)上启动监听器,因为它已经被占用了,我在第二次运行时将应用程序端口更改为 15000,工作得很好,监听器在应用程序正在关闭, 我假设在第一次运行时,端口 14000 上的第一个侦听器在应用程序死后保持打开状态,在第二次运行时,应用程序很好地关闭/打开端口 15000 上的侦听器,为什么会发生这种情况?我想可能是关于端口 14000 我已经切换了打开端口的顺序(首先打开了 15000)并看到 15000 保持打开状态并且 14000(第二次运行)关闭并正确打开,为什么在第一次运行听众没有被关闭?? 我的服务器的代码:

class Server : IDisposable
{
    private const int TIMER_PERIOD = 60 * 1000; // ms
    private string servePort;
    private string serverIP;
    byte[] DataReceived = new byte[1024];
    Action<string> MssageReceiveCallback;
    private bool isListening = false;
    static Timer serverTimer = null;
    private TcpListener _Server;
    private Dictionary<int, TcpClient> clientsList = new Dictionary<int, TcpClient>();
    private bool serverListening = true;
    private static int ClientInstance = 0;


    public Server(string _serverIP, string _serverPORT, Action<string> messageReceiveCallback)
    {
        serverIP = _serverIP;
        servePort = _serverPORT;
        MssageReceiveCallback = messageReceiveCallback;
        // InitilizeServer();
    }

    private void InitilizeServer()
    {

        _Server = new TcpListener(IPAddress.Parse(serverIP), int.Parse(servePort));

        // if (serverTimer == null)
        //     serverTimer = new Timer(new TimerCallback(OnTimerCallback), null, TIMER_PERIOD, TIMER_PERIOD);

        Task.Run(() =>
        {
            try
            {
                _Server.Start();

                while (_Server != null)
                {
                    TcpClient tcpClient;
                    try
                    {
                        tcpClient = _Server.AcceptTcpClient();
                    }
                    catch
                    {
                        continue;
                    }

                    Task.Run(() =>
                    {
                        ClientInstance++;
                        int currentinstance = ClientInstance;
                        clientsList.Add(currentinstance, tcpClient);
                        try
                        {
                            while (tcpClient.Connected && serverListening)
                            {
                                if (tcpClient.GetStream().DataAvailable)
                                {
                                    int actualBufferlength = tcpClient.GetStream().Read(DataReceived, 0, DataReceived.Length);
                                    byte[] data = new byte[actualBufferlength];
                                    Buffer.BlockCopy(DataReceived, 0, data, 0, actualBufferlength);

                                    string asciiMessage = Encoding.ASCII.GetString(data);
                                    MssageReceiveCallback(asciiMessage);
                                }
                                else
                                {
                                    Thread.Sleep(5);
                                }
                            }

                        }
                        catch (Exception ex)
                        {
                        }
                        finally
                        {
                            clientsList[currentinstance].Close();
                            clientsList.Remove(currentinstance);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
            }
        });
    }



    public void StartServer()
    {
        InitilizeServer();
        isListening = true;
    }

    public void SendMessage(string msg)
    {
        byte[] data = ASCIIEncoding.ASCII.GetBytes(msg);
        foreach (TcpClient client in clientsList.Values)
        {
            client.GetStream().Write(data, 0, data.Length);
        }
    }

    public void Dispose()
    {
        serverListening = false;
        foreach (var item in clientsList.Values)
        {
            if (item.Connected)
                item.Close();
        }
        _Server.Server.Close();
    }
}

更新: 我检查了 TCPView 以查看侦听器绑定到哪个应用程序并找到了这个:

看起来监听器可用于不存在的进程

【问题讨论】:

  • 是的,正如您在 Dispose 方法中看到的那样,我正在执行 _Server.Server.Close() 此外,在第二次运行时正确关闭时它没有停止是没有意义的
  • 这里有许多问题可能都会导致问题,但我不能指出一个并说“就是这样”。一个问题是您的clientsList 集合不是线程安全的,并且(另外)您可能正在清除它,而另一个线程正在接受新连接,因为您没有关闭关闭侦听器,直到 您尝试清除该集合。
  • Close 还需要发生一些网络活动,因此如果您调用Close 然后您的进程立即退出,它可能没有时间清理所有内容。
  • 不幸的是它没有用@Damien_The_Unbeliever
  • 您认为我在提供答案?我指出了一些应该解决的问题。如果我相信他们会解决您的问题,我会提供答案,而不是评论

标签: c# networking tcp port tcplistener


【解决方案1】:

你可以试试:

_Server.Server =null;

关闭后。

【讨论】:

  • impossible to set server to null 根据以下错误:“Property or indexer 'TcpListener.Server' cannot be assigned to -- , it is read only”
  • 不必整个进程被拆除时指定null“确保它被GC收集” .
  • @Damien_The_Unbeliever,我的错误......我在修复格式时在编辑中添加了这一点
【解决方案2】:

我认为这里最大的问题(我已经指出了 cmets 中的其他问题)是 TCP 关闭需要网络通信并且默认情况下会在一段时间内阻止套接字重用。 p>

您需要访问的函数是Socket.SetSocketOption,特别是ReuseAddress 选项。您应该能够通过TcpListener 上的Server 属性获得它。请注意,它需要在您真正开始监听器监听之前完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多