拜读了“winsock连续发送信息出现错误”(http://community.csdn.net/Expert/topic/5221/5221493.xml?temp=.8030054)之后,使我意识到需要处理连续发送数据的隐患。我按照jwh2004(兔子)的“设置发送完成标志”的思路,改变了我SendData的机制。可是总是有很多疑问,或者说,我这样改危险性更大。设置了“发送完成标志”的全局布尔变量 gblFlag,窗体Load的时候设定为 True。
每次 SendData 之前,判断这个变量是不是 True。只有True才可以发送。执行了 SendData 之后,将 gblFlag 设为 False。
如果 SendComplete 事件被触发,说明上一条数据已经成功发送了,再将 gblFlag 设为 True,使得第二条可以正常发送。方法1:
    If myWinSock.State = sckConnected Then
        '只有“发送完成的标志”为True时才可以发送新的数据
        '当“发送完成的标志”为False,说明调用方的 SendComplete 事件还没有触发。为了保证成功发送,需要反复循环直到成功发送了数据
        
        Do
            '执行 SendData 方法将数据发送给远程计算机,会触发对方的 DataArrival 事件
            myWinSock.SendData Data:="Hello"
            gblFlag = False            '释放控制权。在释放控制权的期间,调用方的 SendComplete 事件应该被触发,在事件中将 gblFlag 变为 True
            For n = 0 To 1000
                DoEvents
                If gblFlag = True Then Exit For
            End If            If gblFlag = True Then Exit Do
        Loop Until gblFlag = True
    End If
    方法2:
    If myWinSock.State = sckConnected Then
        '只有“发送完成的标志”为True时才可以发送新的数据
        '当“发送完成的标志”为False,说明调用方的 SendComplete 事件还没有触发。为了保证成功发送,需要反复循环直到成功发送了数据
        
        For i = 0 To 100
            '执行 SendData 方法将数据发送给远程计算机,会触发对方的 DataArrival 事件
            myWinSock.SendData Data:="Hello"
            gblFlag = False            '释放控制权。在释放控制权的期间,调用方的 SendComplete 事件应该被触发,在事件中将 gblFlag 变为 True
            For n = 0 To 1000
                DoEvents
                If gblFlag = True Then Exit For
            End If            If gblFlag = True Then Exit For
        Next
    End If
问题:jwh2004(兔子)大侠推荐在事件的代码中不要 DoEvents ,否则会事件重入,程序发生混乱。我同感。
      可是如果不用 DoEvents,程序怎么能够脱身去触发 SendComplete 事件呢?我需要经常性地在 DataArrival 事件中发送数据。      以上的两个方法,我担心一次 DoEvents 恐怕来不及触发调用方的 SendComplete 事件,循环了1千次。
      可是如果因为什么原因,调用方的 SendComplete 事件没有被触发,我的方法1岂不成了死循环?方法2在耗费了大量的CPU资源(循环了10万次)之后还是没有将 gblFlag 变为 True,没有成功发送。
      另外我有点胡涂了,我这两个方法,不会把同样的数据发送多次吧?

解决方案 »

  1.   

    我感觉没有这个必要作一个tcp本身就会做的事情吧 
    霓如果使用 SendComplete 是为了解决数据并发的问题 建议不要这么做 再 senddate 数据&"@#$@#$%"这个消息尾 然后用split()处理同样能解决问题
      

  2.   

    VB不是阻塞模式发送的Senddata, 你有数据只管SendData, VB会帮你缓冲发送, 换句话说, 就是你考虑的太多了, 没这么复杂的, 只管SendData, 有多少Send多少, 我都是这样做的, 没发现什么问题啊
      

  3.   

    zyg0(影子(加班,加班,再加班) 兄的方法,能说得具体一些吗?我没看明白。
      

  4.   

    winsock.senddate 数据 & "s#@$@#$@#%@%"
    接收的时
    dim str as string
    winsock1(index).getdate str
    dim tempre() as string
    tempre=split(str,"s#@$@#$@#%@%")
    dim i as long
    for i=0 to ubound(tempre)
        调用分拣消息方法(tempre(i))
    next
      

  5.   

    谢谢zyg0(影子(加班,加班,再加班)大侠的帮助!我有一点明白了。就是说,如果需要连续发送数据时,不这样写:
        Private Sub myWinSock_DataArrival(ByVal bytesTotal As Long)
            Dim myGetData As String
            myWinSock.GetData myGetData        '如果收到的数据是字符串“Hello”,连续发送两条数据
            If myGetData="Hello" Then
                If myWinSock.State = sckConnected Then
                    myWinSock.senddate 数据1
                    DoEvents                myWinSock.senddate 数据2
                    DoEvents
                End If
            End If
        End Sub而这样写:
        '发送数据的时候将连续发送的数据合并到一起,每条数据中间加上事先约定的消息尾("s#@$@#$@#%@%")
        '接收时再根据消息尾 Split 成数组,分别处理
        Private Sub myWinSock_DataArrival(ByVal bytesTotal As Long)
            Dim myGetData        As String 'GetData收到的数据
            Dim myGetDataArray() As String 'GetData收到的数据按照事先约定的消息尾("s#@$@#$@#%@%")分割成数组
            
            myWinSock.GetData myGetData        '分割成数组
            myGetDataArray = Split(myGetData, "s#@$@#$@#%@%")        '分别处理数组中的每一条数据
            Dim i          As Long
            Dim MySendData As String      '需要发送的数据
            
            For i=0 to UBound(myGetDataArray)
                '如果收到的数据是字符串“Hello”,连续发送两条数据
                If myGetDataArray(i)="Hello" Then
                    If myWinSock.State = sckConnected Then
                        ’将需要连续发送的两条数据合并到一起,每条数据中间加上事先约定的消息尾("s#@$@#$@#%@%")
                        MySendData = 数据1 & "s#@$@#$@#%@%" & 数据2
                        
                        '发送合并后的数据
                        myWinSock.senddate MySendData
                        DoEvents                End If
                End If
            Next
        End Sub是这个意思吧?还剩下几个小问题:
    1、消息尾是可以随便定义的吗?
       昨天我看了你的回复,脑袋马上晕了。很惭愧我对网络编程的理解仅仅是网站和ADO,我还以为这个看似乱码的消息尾是TCP/IP的规定协议呢。可是两次的回复中使用的消息尾不一样(第一次是&"@#$@#$%",第二次是"s#@$@#$@#%@%"),我猜测这是可以自己随意定义的。2、这种加消息尾之后合并数据的方法,和发送数据的WinSock的 SendComplete 事件有关系吗?发送方的 SendComplete 事件中应该怎样处理?3、我一直对jwh2004(兔子)提到的“在事件的代码中不要 DoEvents ,否则会事件重入,程序发生混乱”心有余悸。到底应不应该在 DataArrival 事件中的 SendData 之后加 DoEvents 呢?
      

  6.   

    1 可以随便定义
    2.和哪个事件无关 发送方不需要处理哪个事件 其他都是控件本身的操作
    3 doevents保留
      

  7.   

    我现在写的还是测试程序,有两种发送方式:
    1、在按钮的Click事件中发送。我可以放心地使用DoEvents 。
    2、在 DataArrival 事件中,当收到某一个信息之后作出回应,发送数据。
       比如客户端发送"Hello",服务器端的DataArrival 事件收到之后,再向客户端回应一下,发送一些数据。可能只发送一个字符串,也有可能连续发送多个数据(分包发送)   我担心的是在DataArrival 应该怎样做,用不用 DoEvents 。