【问题标题】:TcpListener.Start() does not open the portTcpListener.Start() 没有打开端口
【发布时间】:2010-03-02 10:35:45
【问题描述】:

我有一个继承自 TcpListener 的类,这个类隐藏 Start 方法只是为了调用基础 Start() 和基础 BeginAcceptTcpClient()。有时会调用该方法但端口未打开(netstat 未显示端口打开)。

类是这样的

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

对正在发生的事情或如何调试问题有任何想法吗?由于无一例外地调用了 Start(),我希望找到始终打开的端口(始终写入日志)。

额外信息:当 Start 方法工作正常时,它每次都工作,直到重新启动应用程序。当 Start 方法不起作用时,它在重新启动应用程序之前不会再次起作用。

编辑:ExtendedTcpListener 处还有一个 Stop 方法:

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

使用 ExtendedTcpListener 的类实现 IDisposable 模式,并在 Dispose 内部调用 ExtendedTcpListener.Stop。

当问题发生时,停止文本不会出现在日志中。

【问题讨论】:

    标签: .net vb.net network-programming tcplistener


    【解决方案1】:

    会不会是在第一次调用 Start 之后,其他方法/线程在 m_stopLock 上获得了锁? (m_stopLock是什么类型的对象?)

    你能用调试器看看是否调用了阴影构造函数吗? (或者在SynchLock之前设置一个trace)

    【讨论】:

    • 不。由于写入了“Extended Tcp Listener started ...”字符串,因此到达那里时不会使用锁。 m_stopLock是一个Object,主要用作启动和停止锁,避免同时启动和停止。
    • “你能用调试器看看是否调用了阴影构造函数吗?”是什么意思。始终调用基本构造函数,因为我唯一的构造函数调用 Mybase.New()
    • 所以我理解:问题不在于某些代码没有被执行( MyBase.BeginAcceptTcpClient(AddressOf Me.CompleteAcceptTcpClient, Me) ),我认为 - 但尽管代码被执行端口还没有打开。这是正确的吗?
    • 没错。代码被调用,但端口未打开。
    【解决方案2】:

    你是不是太快处理对象了?

    我们可以看看您创建 ExtendedTcpListener 实例的代码,以及您是如何管理它的吗?

    【讨论】:

    • 这将是非常罕见的,因为它仅由实现 IDisposable 的另一个类使用,并且该类调用 ExtendedTcpListener Stop 方法,该方法具有另一个写入“Extended Tcp Listener Stopped ...”的日志(此文本问题发生时当然不存在)。无论如何,我会将代码作为编辑。
    【解决方案3】:

    这很奇怪,好吧。据我了解,一旦问题开始出现,您可以轻松重现它,对吗?如果是这样,我会在那时将调试器附加到它并检查 TcpListener 对象及其底层 Socket (m_ServerSocket)。我无法在此给出准确的说明,您只需要查看它,看看是否有任何地方不合适或与工作时的方式不同。

    【讨论】:

      【解决方案4】:

      您从TcpListener 继承并使用Shadows 覆盖非虚拟方法对我来说看起来很危险。您是否尝试将代码更改为不从 TcpListener 继承,而只是封装它?

      编辑:添加示例代码

      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
      

      【讨论】:

      • 为什么看起来很危险?阴影就是要以这种方式使用的,不是吗?
      • Shadows 就像在非虚拟(非可继承)方法上“强制”覆盖。这打破了多态性:如果您将 ExtendedTcpListener 传递给需要 TcpListener 的方法(或简单地将其分配给声明为 TcpListener 的变量),则将调用 TcpListener 类的 Start 和 Stop 方法而不是您的覆盖。 “阴影”是邪恶的,避免它像地狱一样 - 尝试封装而不是这样继承。
      • 好的,我明白了,无论如何这不是问题,因为该类始终用作 ExtendedTcpListener 并且只使用一次。还是谢谢。
      猜你喜欢
      • 2021-09-20
      • 1970-01-01
      • 1970-01-01
      • 2021-01-23
      • 1970-01-01
      • 1970-01-01
      • 2020-09-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多