VB的winsockTCP/IP连续发送数

字体大小: | |
已经差不多过完年了,又要开始忙了,新的一年新的开始,希望今年的目标能实现。
很久没有写技术文章了,说点老技术,也就是标题中所说的,用VB的winsock发送数据(TCP/IP)连续发送数据时,有可能出现以下情况:

(以下提到S端为服务端,C端为客户端)

1、有些客户机可以接收数据,有些客户机接收不到数据。
2、客户机都收不到数据。
3、会收到多条数据(多条指的是1条,或者1条以上的数据,数量也并非整数)

已经记不清概念了,只是记得这个原理。先看代码片段:
Function SendDataToClientMachine()
'以字符串方式发送
'Server 端
dim strSendData as String
strSendData="never-online,http://www.never-online.net"

tcpserver.sendData "SEND:" & strSendData
'多客户机用winsock数组实现,具体代码略过,原理相同
DoEvents
End Function

客户机代码片段
Function RecieveData()
'以字符串方式接收
'Client 端
If tcpClient.State <> sckConnected Then GoTo skip
Dim data As String
if left(data,5)="SEND:" then Call RecieveCallBack(Mid(data,6))
skip:
End Function

Function RecieveCallBack(byval data as variant)
data=data & ""
debug.print data
End Function
通常以这种方式发送应该是正常的。但频率足够快时,比如,10次/秒,将会出现文中开始所提的问题:

正常时接收到的字符串:
"SEND:never-online, http://www.never-online.net"

非正常时:
1、有些客户机可以接收数据,有些客户机接收不到数据。
多客户机时,当频率很快时,用winsock数组(假设当前连接数为10),发送到第5个客户机,此时主线程又有新消息,即再次发送数据执行SendDataToClientMachine函数。又再次用Doevents交给操作系统处理。而后面5个客户机就会没有接收到数据了。

2、客户机有可能都收不到数据。
因为有一个Flag的关系("SEND:"字符串),客户机必须在前5个字符串中验证是否是"SEND:",如果不是则不会调用RecieveCallBack函数。这是由于原因3造成的。但这种情况较少发生,一般是有的可能接收,有的接收则不成功。

3、会收到多条数据(多条指的是1条,或者1条以上的数据,数量也并非整数)
举个简单的例子,比如2个客户机,发送次数过多时,调用完一次SendDataToClientMachine函数,立即再次又调用SendDataToClientMachine函数,这次并不会阻塞。便可能出现这样的字符串
"SEND:never-online, http://www.never-online.netSEND:never-online"
也可能出现这样的字符串
"SEND:never-online, http://www.never-online.netSEND:never-online, http://www.never-online.net"
也就是说,“成堆”现象。出现混乱局面。这都是连续发送频率过快时出现的

原理说明:
正确的TCP/IP接收方式是S端发送,C端接收,C端发送消息,如“OK”表示接收成功。这样S端便知道C端是接收成功的,但这得具体场合具体分析了。还是回头来讨论上面问题出现的原理。
VB winsock在以TCP/IP发送数据时, 不是阻塞式的,而是只要客户机有足够大的缓冲区接收服务机发送的数据,便会一直存储数据,也就是出现问题3。换句话说,不是S端发送,未发送毕时winsock阻塞,C端立即接收。(TCP运行在IP之上,是基于数据流连接和面向的协议,应用程序把数据要经过TCP/IP的分割成若干包,这样数据就以字节流发送和接收,到达目的地后,TCP/IP 再按顺序进行组装。TCP/IP 要保证机器与机器之间的连接的可靠性,还要有纠错。TCP是否被选择,取决于应用程序或服务;)

并非象UDP中这样的发送方式/接收方式。象TCP一样运行在IP之上,UDP是基于数据报或分组的协议,UDP/IP 可以直接发送和接收数据报文,而不必做验证,这一点与TCP/IP 不同

大体在本文讨论中。TCP是牺牲速度换安全的。

解决方法
1、为保证数据正确传输,可以在S端中tcpserver_SendComplete事件中加入全局标志,如果发送完毕,置为true,否则为false。当连续发送频率过快时,此方法有可能会一直阻塞发送。(全局标志一直处理false状态,导致不能发送)

2、 当发送频率过高时,一般情况下很多是重复数据发送过去。为保证数据包的完整性和正确性,可以这样做,如果面SendToClientMachine函数中发送的格式是
tcpserver.sendData "SEND:" & strSendData
我们改成
tcpserver.sendData "SEND:" & strSendData & ":SENDEND"
即两个Flag,一个头,一个尾。
虽然客户机依然可能收到如"SEND:never-online, http://www.never-online.net:ENDSEND:never-online"这样的字符串,那么这条就不处理。直到数据包为
SEND:never-online, http://www.never-online.net:END"
这样的形式,经过测试,这个方法基本可行。

3、换成UDP协议方式发送,如果允许的话。

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...