VB6 Winsock 多个 TCP 连接 > DoEvents 问题

Posted

技术标签:

【中文标题】VB6 Winsock 多个 TCP 连接 > DoEvents 问题【英文标题】:VB6 Winsock multiple TCP connections > problems with DoEvents 【发布时间】:2016-05-31 05:56:39 【问题描述】:

几年前我使用 VB6 制作了一个软件,它用作 TCP 服务器,接收来自客户端的多个连接。

该软件的基本思想是监听特定端口,接受来自不同客户端的连接并将每个连接传递给单独的winsock,该winsock分析数据,查看数据库,以适当的方式回复消息,然后关闭连接。

这里有一些代码:

在应用程序启动时初始化套接字:

For i = 1 To MaxCon    
    Load sckAccept(i)
Next i
sckListen.Listen

接受连接:

Private Sub sckListen_ConnectionRequest(ByVal requestID As Long)
    Dim aFreeSocket As Integer
    aFreeSocket = GetFreeSocket
    If aFreeSocket = 0 Then
        sckAccept(0).Accept requestID
        sckAccept(0).SendData "Server is full!"
        sckAccept(0).Close
    Else
        sckAccept(aFreeSocket).Accept requestID        
End Sub

接收数据、分析数据并回复:

Private Sub sckAccept_DataArrival(Index As Integer, ByVal bytesTotal As Long)
    Dim sData As String  
    sckAccept(Index).GetData sData
    'Do lots of analyizing and search in DB
    '
    '
    sckAccept(Index).SendData "Message"
    '
    '
    DoEvents
    sckAccept(Index).Close
End Sub

一切正常,但现在连接数增加了(每秒几十个),所以软件开始出现Out of stack space 异常(因为DoEvents)。

我知道在很多情况下DoEvents 是邪恶的,但如果我删除它,应用程序 UI 将不会响应(因为线程上的负载过重)并且可能无法传递一些数据。

所以,我的问题是:有没有人知道如何使用/不使用DoEvents 来解决这个问题?


注意:我知道 VB6 并不真正支持多线程,并且可能是这种情况下的 PITA。我实际上计划升级软件并使用.Net 重新创建它,但这需要一些时间。这就是为什么我需要在 VB6 中解决这个问题,因为该软件目前是用 VB6 编写的。

【问题讨论】:

我真的不明白为什么 doevents 应该在 dataarrival 处理程序的最后一行,我会把它放在沉重的循环中。从技术上讲,doevents 做了一个简单的“yield”,因此,堆栈外错误可能有另一个来源,比如 sdata 的大小,我会将它放在外面的数组中并使用连接索引访问它,我完全理解这是脏的,但应该有助于节省一些堆。 1- 我将DoEvents 放在DataArrival 处理程序中,因为它会触发Winsock.SendData 和“如果我删除它,应用程序UI 将不会响应(因为线程上的过载) 并且某些数据可能无法交付”。 2-“重载”是什么意思? 3- 当Out of stack space 错误发生时,堆栈中充满了sckAccept_DataArrival 事件。我假设这是因为DoEvents 允许再次触发事件(其中包含另一个DoEvents,等等)。 4- sData 的大小非常小(40-100 字节) 我完全理解你为什么使用 doevents,我只是在 sub 的末尾没有看到它,我习惯在循环内“doevents”,这样循环就不会锁定应用程序。即使 sdata 很小,您也只能赚取一些空间将其放在外面而不会丢失任何内容。我也明白导致您的问题的原因是一堆未回答的 tcp 查询(因为他们的处理程序正在为他们查询数据库)。 DoEvents() 调用比“yield”远远超过,并且在使用引发外部事件的控件(主要示例是 Winsock 控件)的程序中对这些的任何使用都是一个错误。如果您有阻止事件处理的 QBasic 样式代码块,则需要重写它们。没有简单的建议可以解决您的问题,您需要有经验的程序员来看看它。 【参考方案1】:

嗯,我设法找出问题所在,并且已经解决了。

简短回答

不要使用DoEvents.. 某些数据不会被传递?好吧,只在SendComplete 事件中关闭连接。


长答案

第一件事:

为什么我首先使用DoEvents?因为某些已发送消息没有被传递。网上很多文章/问题建议在Socket.SendData之后使用DoEvents,以保证数据到达接收者。

我对此进行了更深入的研究,试图找出消息未送达的原因。我发现这个问题只有在发送消息后关闭连接时才会出现:

Socket.SendData "Message"
'
'
Socket.Close

所以,我只是将关闭连接的行移至SendComplete 事件,删除了DoEvents 语句-因为我不再需要它-,问题就消失了:)

Private Sub sckAccept_SendComplete(Index As Integer)
    sckAccept_Close (Index)
End Sub

我希望这可以帮助遇到同样问题的人。

【讨论】:

没有帮助我,而是 +1 为我们回答您自己的问题。

以上是关于VB6 Winsock 多个 TCP 连接 > DoEvents 问题的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 VB6 Winsock 连接到票务打印机

VB6:如何获取通过 winsock 发送的字节数?

VB6 中的默认 WinSock 协议

vb6 winsock 连接而不是每个设备的无限客户端减少到 2

VB6 中的 Winsock 控件只向数组中的最后一个索引发送文本消息

如何通过 Winsock 从外部设备检索数据到 Microsoft Visual Basic (VB6)