1

I have an issue with my application, I have a TCPListener which listen let's say on port 14000 After the application is being closed I can see on the CMD that the listener is still listening. At the second run of the application as expected I cant start the listener on the same port (14000) because it is already taken, I am changing the application port to 15000 on the second running, work wonderful and the listener is being CLOSED after the application is being shut down, I assume that on the first run, the first listener on port 14000 stays open after the app is dead, on the second run the application closed/open the listener on port 15000 very well, why is this happen? I thought maybe it is about the port 14000 I've switched the orders of the opening ports (first opened 15000) and saw that the 15000 stays open and the 14000 (on the second run) closed and open correctly, Why at the first run the listener not being closed?? The code to my server:

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();
    }
}

UPDATE: I've check in TCPView to see which application the listener bind to and found this: enter image description here

It looks like the listener available for un exist process

DBS
  • 151
  • 2
  • 18
  • Yes as you can see in the Dispose method I am doing _Server.Server.Close() Also, not make sense it is not stopping when on the second run it is closing correctly – DBS Jul 25 '18 at 09:20
  • There are a number of issues here that may all be contributing problems but I can't point to one and say "that's it". One concern is that your `clientsList` collection isn't thread safe and (separately) you might be clearing it down whilst another thread is in the middle of *accepting* a new connection, since you don't shut down the listener until *after* you've attempted to clear that collection. – Damien_The_Unbeliever Jul 25 '18 at 09:51
  • `Close` also requires some network activity to occur, so if you're calling `Close` and then your process immediately exits, it may not have had time to clean everything up. – Damien_The_Unbeliever Jul 25 '18 at 09:53
  • Unfortunately it didn't work @Damien_The_Unbeliever – DBS Jul 25 '18 at 10:22
  • From "may all be contributing" you thought I was offering an *answer*? I was pointing out a number of issues that ought to be fixed. If I believed that they would solve your problems, I would have provided an *answer*, not a *comment*. – Damien_The_Unbeliever Jul 25 '18 at 10:26

2 Answers2

1

The biggest problem here, I think (I've pointed out other problems in the comments) is that TCP shutdown requires network communications and by default prevents socket reuse for a period of time.

The function you need to get to is Socket.SetSocketOption, specifically the ReuseAddress option. You should be able to get at it via the Server property on the TcpListener. Pay attention that it needs to be done before you actually start the listener listening.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
-1

You could try putting:

_Server.Server =null;

After close.

ScottishTapWater
  • 3,656
  • 4
  • 38
  • 81
CorrM
  • 498
  • 6
  • 18
  • impossible to set the server to null according to the following error: "Property or indexer 'TcpListener.Server' cannot be assigned to -- , it is read only" – DBS Jul 25 '18 at 09:43
  • You **do not** have to assign `null` to "ensure that it gets collected by the GC" when the *entire process is being torn down*. – Damien_The_Unbeliever Jul 25 '18 at 09:46
  • @Damien_The_Unbeliever, my mistake... I added that in an edit when I was fixing the formatting – ScottishTapWater Jul 25 '18 at 10:16
  • u can look here https://stackoverflow.com/questions/365370/proper-way-to-stop-tcplistener – CorrM Jul 25 '18 at 10:20