views:

351

answers:

4

Hello,

I have a class that inherits from the TcpListener, this class Shadows the Start method just to call the base Start() and the base BeginAcceptTcpClient(). From time to time the method is called but the port is not opened (netstat does not show the port open).

The class looks like this

Public Class ExtendedTcpListener
    Inherits System.Net.Sockets.TcpListener

Public Shadows Sub Start()
    SyncLock (m_stopLock)
        MyBase.Start()
        MyBase.BeginAcceptTcpClient(AddressOf Me.CompleteAcceptTcpClient, Me)
        My.Application.Log.WriteEntry("Extended Tcp Listener started ...", TraceEventType.Verbose)
    End SyncLock
End Sub

Any idea on what's happening or how to debug the issue? As the Start() is called without exception I expected to find the port always opened (the log is always written).

Extra information: when the Start method works fine it works each time until app is restarted. When the Start method does not work it won't work again until the app is restarted.

Edit: There is also an Stop method at the ExtendedTcpListener:

Public Shadows Sub [Stop]()
    SyncLock (m_stopLock)
        MyBase.Stop()
        My.Application.Log.WriteEntry("... extended Tcp Listener stopped", TraceEventType.Verbose)
    End SyncLock
End Sub

The class that uses the ExtendedTcpListener implements the IDisposable pattern and inside the Dispose the ExtendedTcpListener.Stop is called.

The stop text is not present at the logs when the problems happens.

A: 

Could it be that after the first time Start is called other method/thread gets a lock on m_stopLock? (what type of object is m_stopLock?)

Can you look with the debugger and see if the shadowing constructor is called? (or set a trace before SynchLock)

Ando
Nope. As the "Extended Tcp Listener started ..." string is written the lock is not taken when getting there. The m_stopLock is an Object used mainly as the start and stop lock, to avoid starting and stopping at the same time.
SoMoS
What do you mean with "Can you look with the debugger and see if the shadowing constructor is called?". The base constructor is always called because my only constructor calls Mybase.New()
SoMoS
So that I understand: the problem is not that some code does not get executed ( MyBase.BeginAcceptTcpClient(AddressOf Me.CompleteAcceptTcpClient, Me) ), which I thought - but that although the code gets executed the port is still not open. Is this correct?
Ando
That's rigth. The code gets called but the port is not opened.
SoMoS
A: 

Aren't you disposing the object too soon?

Can we see the code where you create an instance of ExtendedTcpListener, and how you manage it?

Fábio Batista
It would be very rare because it is used only by another class that implements IDisposable and this class calls the ExtendedTcpListener Stop method that has another log that writes "Extended Tcp Listener Stopped ..." (this text of course is not present when the problem happens). Anyway I will put the code as an edit.
SoMoS
A: 

This is a weird one, alright. As I understand, once the problem starts to occur you can reproduce it easily, right? If so, I would attach the debugger to it at that point and inspect the TcpListener object and its underlying Socket (m_ServerSocket). There are no precise instructions I can give here, you just have to look at it and see if anything seems to be out of place or just different to the way it is when things are working.

Evgeny
A: 

It looks very dangerous to me that you are inheriting from TcpListener and overriding a non-virtual method using Shadows. Have you tried to change your code to NOT inherit from TcpListener, but just encapsulate it?

Edit: added sample code

Public Class ExtendedTcpListener
  ' Inherits System.Net.Sockets.TcpListener <== DO NOT INHERIT

  Private MyTcpListener As New TcpListener()

  Public Sub Start()
    SyncLock (m_stopLock)
      MyTcpListener.Start()
      MyTcpListener.BeginAcceptTcpClient(AddressOf Me.CompleteAcceptTcpClient, Me)
      My.Application.Log.WriteEntry("Extended Tcp Listener started ...", TraceEventType.Verbose)
    End SyncLock
  End Sub

  ' ...
End Class
Fábio Batista
Why looks dangerous? Shadows is meant to be used in this way isn't it?
SoMoS
Shadows is like "forcing" an override on a non-virtual (non Inheritable) method. This breaks polymorphism: if you pass your ExtendedTcpListener to a method that expects a TcpListener (or simply assign it to a variable declared TcpListener), the Start and Stop method of the TcpListener class will be called instead of your override. "Shadows" is evil, avoid it like hell - try to encapsulate instead of inherit this way.
Fábio Batista
Ok, I see the point, anyway that's not the problem here because the class is always used as ExtendedTcpListener and is only used once. Thanks anyway.
SoMoS