For i = 0 To sckClient.UBound
If sckClient(i).State = 7 Then
sckClient(i).SendData sR
DoEvents
End If
Next
我不想用 DoEvents ,,哪位 神仙 有办法呀????
因为
比如在FOR 循环的过程中,突然系统有别的事件发生,它就会跑去处理别的事情了
如果这样的别的事情太多,,那我的FOR 循环 还要不要工作呀,,我只是举个例子说明不想用Doevents甚 期盼 神仙级别的 高手 来救我一次呀
If sckClient(i).State = 7 Then
sckClient(i).SendData sR
DoEvents
End If
Next
我不想用 DoEvents ,,哪位 神仙 有办法呀????
因为
比如在FOR 循环的过程中,突然系统有别的事件发生,它就会跑去处理别的事情了
如果这样的别的事情太多,,那我的FOR 循环 还要不要工作呀,,我只是举个例子说明不想用Doevents甚 期盼 神仙级别的 高手 来救我一次呀
不用 devents也行 用 一个事件 在那里面发送 不错处理起来麻烦 还要 加消息头和尾
麻烦你能不能详细的说说这个方法,好吗? 虽然用了这么久VB,但是有些 队列 什么的,还不会
所以 还得先用VB解决了,,,,以后再漫漫用VC 增强功能
难道你就是那个 我曾经下载过你的很多程序 的 超级绿豆吗 ???
-----不过感觉不是吧,,,超级绿豆 会不知道 我为什么必须在一个FOR 循环里 ,很无奈地,很不情愿地加上Doenents 吗?!
回答: 我不想加Doenents,但必须在那里加Doenents,,原因是这是Visual Basic 的 WINSOCK 6.0
如果你不想for被打扰,就搞多线程吧...
从第一句看来,你确实不是对WINSOCK 6.0 很透彻
第2句话,值得研究,,,可是VB的多线程 经得起考验吗? 程序是给客户安装用的,不是自己编个多线程玩玩,,
要长期经得起运行考验的。 我在这只是想求助的,,说话没有半点 难为 OR 讽刺 OR 偏激 的 意思或行为。 只针对问题发表意见,,请谅解。
如果有些朋友提出了好的思路,,能够再详细些,或者能够带上部分 代码,那就感激不尽了。
If sckClient(i).State = 7 Then
sckClient(i).SendData sR
DoEvents
End If
Next 不想用也可以不用呀 ,你不用DOEVENTS,同样也可以发送数据,不过这样发送的数据也许好多个SR组成一个大包,大概是8K后一起发送出去,.如果你加头尾标志的话,在接收端也很容易分离各段数据!
嘻嘻,你还可以看出其中的端倪, 说话也比较风趣 恩
2、VB是单线程的,你在这里不能使用阻塞式的循环或其他类似的东西,否则就算等到宇宙毁灭的时候,你也不会看到这个程序恢复响应。
3、照我的理解(当然,我的感觉在大部分时候都是错的),你这里是想将SendData的异步操作改为同步。因此,我粗略地想了一下(当然,我向来都很粗的),希望下面这种方法对你的问题是否有所帮助Private Sub MySendData(ByVal Index As Integer)
With sckClient(Index)
If .State = sckConnected Then
.SendData CStr(Index) & ">" & Text1.Text & CStr(Index)
End If
End With
End Sub
Private Sub sckClient_SendComplete(Index As Integer)
If Index < sckClient.UBound Then
MySendData Index + 1
End If
End Sub
Private Sub Command1_Click()
MySendData (sckClient.LBound)
End Sub
在这里DoEvents的作用就是让send函数有时间依次把缓冲区里的数据发完,否则后面的SendData所写入的数据会被并到前面的缓冲区中。因此,实际上解决这个问题的最关键之处就是,在调用SendData发送大数据前,对其进行分段处理;在接收到分段数据后,进行组装。
首先,SendData将数据根据大小分段,段的大小为&H2000(8K)。而后,调用send函数把分段后的数据一点点写入缓冲区发掉。 在这里DoEvents的作用就是让send函数有时间依次把缓冲区里的数据发完,否则后面的SendData所写入的数据会被并到前面的缓冲区中。------[你的见解是对的]
因此,实际上解决这个问题的最关键之处就是,在调用SendData发送大数据前,对其进行分段处理;在接收到分段数据后,进行组装。------[参考 ZOU_SEAFARER:‘又仔细的看了你的要求,我发现我说错了,我理解为你的数据是数组而非你的WINSOCK数组,当我没有发言,哈哈’]
我再测试下
的VB.net的方法 ,也是有缺陷呀。
当客户端(sckClient)很多,当它们发送数据的频率 很高的时候,,,就会出现问题了,,有些只能发给一个客户端(sckClient),,,因为其他的socket过来了,将INDEX 参数冲了?
从这方面看, 是不是Private Sub sckClient_SendComplete(Index As Integer) 也是中间有个转让系统时间的过程? 那么它本身也就相当于一个Doevents了 !!!
在于 VB里只能用那个Doevents了,,,,没招了!
你怎么现在还没有认识清楚 我现在的窘境 所在吗?
问题根本不是出在“应该在发送端和接收端都加上分包和组包处理代码”之上! 你说的那是对于发送大文件的处理方法!! 我是一堆 WINSOCK数组 逐个地向外发送数据 ,不是一个WINSOCK 向外发送一堆数据。 “再增加一个发送控制命令的winsock。这样就可以完全确保你的数据是按照顺序发送的了。”这句话我不能完全理解它要怎么思路呀
不过在VB使用WinSocket API比较麻烦,因为没有相关的定义,需要自己来定义,如果你熟知C++数据类型和VB数据类型的转换就好办了。
哈里卤鸭! TCP, 接收端没有重复的 lyserver:
用 WinSocket API 是解决的正途 呀
能发个小Demo供调研下吗? [email protected]
目前正在研究VC的IOCP,C++还能看动点
哇哈哈哈------------俺的口号
http://topic.csdn.net/u/20080317/10/35c09da5-fe48-4f1a-93de-f5f8c68fc88d.html
winsock服务端请求排队与事件响应难题,非要开多线程吗?请高手指点
本来我对这个 帖子 也不抱 太大的奢望,都苦恼了那么久了,也深知道问题不是那么好解决,,可以说,如果不用lyserver 兄弟说的WINSOCK API, 已经没有希望了!!!
但是至于 把问题看偏了方向,,或者没有很深入的测试调试情况下 说出来的方法,我包括看过这个帖子的人都会感谢你能拿出自己的见解和别人分享! 但是有些看似很有道理,但是经不起推敲,,,,
程序就是这样,只要你有想不到的地方,只要有充足的时间,它都会给你暴露出来的。
关于startbin 说的第一个问题: 前面已经说过,不是数据太大的问题,,而且我实际应用中给每个客户端每次发送的数据包都不大,也就几百个字节吧 ! 所以也就不存在分包了,当然也不用加协议报头/报尾了。
关于startbin 说的第二个问题: 前面绿豆提出这个思路的时候,我就测试了,在客户端数量巨大的情况下,有很多客户会有很多本来应该收到的数据,原因我前面也说了,,如果你愿意可以实际做一下,,,, 在这里感谢大家的积极讨论,,ZOU_SEAFARER 兄弟说的可能也对,,因为VB有它的局限性 ,,但是也并不能说完全没有了希望了,, 我也在一直调试VC的完成端口,,但我不会轻易放弃的,毕竟VB用起来顺手。
还有,,嗷嗷叫的老马:请教个问题, 我测试将WINSOCK 放在ACTIVE EXE 里面,怎么不能用呢,老是出错! 你如果测试可以用的话,能告一下吗?
你说的shutdown是什么呢? 能否具体些?
shutdown()函数我在VC里面见到过,VB里的是起什么作用的呢,无知中,能否详解告知!
另外,,48楼发言纠正:"有很多客户会有很多本来应该收到的数据,"-----应该为"有很多客户会有很多本来应该收到的数据,收不到了,原因"
我没有发现你所说的现象呀.对于这个ActiveX EXE,我也研究不多,等于是刚接触.我利用这刚学到的一点知识写了一个下载程序的例子,看看能不能引一下玉:http://www.m5home.com/blog/article.asp?id=65
:)
我的客户端 不是在一个程序里的,,是分布在很多台机器里,每台机器里有一个客户端,每个客户端里有一个接收WINSOCK
下载了,先调试,看尽量向这方面靠,,能否有突破!
嗷嗷叫地 谢谢 嗷嗷叫的老马,先! 别的同志也可以帮忙向这方面凑,看多线程 或 ACTIVE EXE 能否缓解问题,能否稳定!
shutdown sckClient(Index).SocketHandle, SD_SEND这样的话,可以保证数据马上被发送采用多线程或多进程对你的问题似乎也不会有什么太大的帮助。因为不管你上面怎么发送,最后都是要归到同一个底层缓冲的。另外,你可以调用WSASend函数使用完成端口
再问个深一点的问题:VB的调试中,暂停和开始功能实际上VB做了些什么???比如你窗体有个TRIMER控件,调试暂停,我想应该是TRIME.ENABLED=FALES,再开始,应该是.ENABLED=TRUE了,但对SOCK控件VB做了什么?因为我发觉排队在端口的包,只要暂停、开始后,DataArrival又被触发了。
TCP协议理论上是可以保证发送数据的完整性,如果数据发送过程中因各种原因造成数据发送失败,winsock会尝试重新发送。这里doevents的作用究竟是为什么?我觉得如果是为了清除缓冲区数据似乎说不过去,因为当数据大于8k的时候,winsock无需人工干预会自动分包发送,如果这个过程要doevents来帮助完成,好象联机帮助中并没有说循环发送中数据doevents是必须的,而且从简单测试来看,不加doevents是可以的。所以我觉得doevents更多的作用还是为了防止在循环发送数据过程中,因种种原因造成程序的假死状态
我还是比较赞同要发送数据的处理问题,发送端接收端包的处理是关健
测试了你提供的新的方案,觉得值得研究。
本来下载过几个纯SOCKET API 编写的SOCKET,,以为若要使用SOCKET API,就必须完全的用SOCKET API做出一个SOCKET控件,然后在程序里调用自己写的这个SOCKET控件,才可以使用SOCKET API 。 呵呵,,看来还是自己的固定思维以及懒惰的心态 不好呀!
测试了,但是还有问题:就是我发送的数组内的内容,,与客户端接受的内容 完全不一样; 只是客户端接受的长度与 我发送的长度一样。 可能是发送的缓冲区 有问题?
supergreenbean,你的这两个函数里面的参数,你能不能用具体的例子 表示一下
send sckClient(Index).SocketHandle, ByVal sSend, Len(sSend), 0
shutdown sckClient(Index).SocketHandle, SD_SEND 我刚查了VC里面,知道 #define SD_SEND 0x01
1、数据到达socket,系统投递 FD_READ消息到VB的NMNotifyXXX窗口
2、VB应用程序在处理一些其他消息的过程中,调用ioctlsocket(s, FIONREAD...)提示有数据可读
3、VB应用程序使用recv读取数据
3、应用程序继续处理消息,直至下个FD_消息到来所以,我认为,事件之所以没有被触发是因为主线程在处理消息的时候堵塞了,从而造成接收不畅。
我的帖子也成了onetiger1243 的帖子?
Dim sMsg As String
Dim i As Long
For i = 0 To sckClient.UBound
sMsg = "<" & Format(i + 1, "000") & ">" & Text1.Text
With sckClient(i)
If .State = sckConnected Then
send .SocketHandle, ByVal sMsg, Len(sMsg), 0
shutdown .SocketHandle, SD_SEND
' .SendData sMsg
End If
End With
Next
MsgBox "Sent"
End Sub
另外:WSAsend作为非阻塞方式,一定要包含OVERLAPPED参数吗? ---也就是说如果我想用WSAsend作为非阻塞方式,非要求用完成端口吗?? BAIDU了会,,也没有查出结果。 我想用 非阻塞方式 向外发送,,,更想用完成端口的方式 向外发送 (本楼 都特指在VB下调用),,但觉得VB下的完成端口 不可能处理好吧?? 所以,退一步求: 能用非阻塞方式 向外发送吗? 我自己试验了下,ErrorCode = WSASend(sckClient(i).SocketHandle, ByVal Bfr, 1&, len, Flags, 0,0&) 发送了,,可是客户端什么也没有收到!
shutdown()函数用于任何类型的套接口禁止接收、禁止发送或禁止收发。
如果how参数为0,则该套接口上的后续接收操作将被禁止。这对于低层协议无影响。对于TCP协议,TCP窗口不改变并接收前来的数据(但不确认)直至窗口满。对于UDP协议,接收并排队前来的数据。任何情况下都不会产生ICMP错误包。
若how为1,则禁止后续发送操作。对于TCP,将发送FIN。
若how为2,则同时禁止收和发。
请注意shutdown()函数并不关闭套接口,且套接口所占有的资源将被一直保持到closesocket()调用
-------------------------------------------------------------------------------------
不太明白 你为什么 要调用shutdown()函数呢?
原谅我的懒惰,是在不想分析以上的代码。看了下我以前写的一些SOCKET服务器,好像的确没用到“Doevents"(如果这屎一种罪的话~~呵呵)解决问题的思路大致如下:[color=#FFFF00]1.首先建立一个Winsock控件的数组:我代码里面是 Winsock1(0)[/color]2.然后使Winsock1(0).listen3.在有客户端接入的时候,Load一个新的WinSock1控件Winsock1(n+1)进行处理,原来的Winsock1(0)一直起到listen的作用
Private Sub Winsock1_ConnectionRequest(Index As Integer, ByVal requestID As Long)
load Winsock1(n++) //n是接入的客户数目,可以起到控制同事接入的客户端的作用。到一定可以清1
Winsock1(n+1).accept(requestID )
End Sub4.在Winsock1_DataArrival事件里面处理工作Private Sub Winsock1_DataArrival(Index As Integer, ByVal bytesTotal As Long)
。
End Sub以上代码都是凭记忆写,可能语法有问题,但是主要屎为了叙述一下我的思路。基本能够实现多线程的处理!
Private Sub Winsock1_ConnectionRequest(Index As Integer, ByVal requestID As Long)
load Winsock1(n++) //n是接入的客户数目,可以起到控制同事接入的客户端的作用。到一定可以清1
Winsock1(n+1).accept(requestID )
End Sub
4.在Winsock1_DataArrival事件里面处理工作
Private Sub Winsock1_DataArrival(Index As Integer, ByVal bytesTotal As Long)
。
End Sub 以上代码都是凭记忆写,可能语法有问题,但是主要屎为了叙述一下我的思路。基本能够实现多线程的处理!
幽幽地问一下:shakoe,你的这代码 是干什么的??好象与我提出的问题 无关吧。
你说的一个SOCKET的侦听,另外一个SOCKET数组accept(requestID),,,貌似 “地球人都知道”呀 继续郁闷
你说的一个SOCKET的侦听,另外一个SOCKET数组accept(requestID),,,貌似 “地球人都知道”呀
.....
感谢网事如峰的好贴,我的问题真的是和你到一起了....
我用了个SockMon的侦听软件,原来真的是SOCK的端口阻塞,更正我在55楼的说法,不是DataArrival不触发,而是DATASEND没有做.也就是该发的数据没有发..原因是服务器忙......
在SOCK的记录中看到开始运行时服务端能同时运行几个进程,但几秒钟后就被其中一个进程独专了,直到该进程完成.......
61楼超级绿豆的代码还有点不明白,SEND 和shutdown分别是什么,在VB6下怎么不能直接用?要引用什么吗?
因为我发觉排队在端口的包,只要暂停、开始后,.SENDDATA又被触发了。
引用楼主的原话就是:
有很多客户会有很多本来应该收到的数据,收不到了,原因"
WSASend如果最后两个参数都是0,那么它的行为就与send一样。
Private Declare Function WSASend Lib "ws2_32.dll" (ByVal s As Long, buf As Any, ByVal dwBufferCount As Long, lpNumberOfBytesSent As Long, ByVal dwFlags As Long, lpOverlapped As Any, lpCompletionRoutine As Any) As Long
Private Type WSABUF
len As Long
buf As String
End Type...Dim tBuf As WSABUF,lBytesSent As LongtBuf.buf = sSend
tBuf.len = Len(sSend)Debug.Print WSASend(sckClient(i).SocketHandle, tBuf, 1, lBytesSent, 0, 0, 0)
如果使用完成端口,貌似要使用fAlertable参数为1的WSAWaitForMultipleEvents等API函数将线程置为alertable wait的状态还有,Winsock控件本身的发送方式就是异步的重叠IO操作
supergreenbean:
WSASend(sckClient(i).SocketHandle, tBuf, 1, lBytesSent, 0, 0, 0)这样的应该也属于 同步了吧,,不喜欢啊!
我需要异步的WSASend: 即我只管把 数据发送出去就可以了,就立即返回,让系统处理真正的发送!
这样的WSASend 能举个例子吗?
1,对SOCK的发送端,完全没必要对大文件进行分段,分段操作,既浪费了系统资源,还减慢了发送速度。如果说是为了保证发送数据的准确性,只需要对整个文件进行加包头包尾,如果整个文件会丢包,分开发也会丢包,那是网络问题,因为TCP的确认机制基本能保证数据的准确性。
2,对于SOCK的发送堵塞问题,我还是理解为系统问题,而不是SOCK本身,因为我只是把分段发送改成整个发送,让SOCK自己去分段。问题就解决了,同时10来个连接,发送同一个20M左右的文件,都只要2-4秒。
3,WINSOCK的API没时间试了,还有堵塞问题,不是我不求甚解,我在这个问题上消耗了太多时间,接下来有好多事情,等空一点再好好烟酒烟酒
4,多谢几位老大的支持和UP,真心感谢这段弯路。到VB控件我的贴去领分,呵呵虽然我知道你们也不在乎几个鸟粪。
SendData的实际执行流程是这样的:1、调用SendData方法
2、Winsock判断数据大小
3、如果大于8K,则先取前面8K数据;如果小于8K则取全部数据
4、调用API send,发送数据,并得到已发送数据长度 -> bytesSent=send (s,buf,len,0)
5、调用SendProgress事件。将 已发送数据长度 bytesSent和剩余数据长度 bytesRemaining作为事件参数
6、判断剩余数据长度bytesRemaining是否为0
7、如果还有数据,则继续返回第2步;否则,跳出循环
8、调用SendComplete事件WSASend的异步发送方式我还没试验过,不好说,估计实现上会有些麻烦事
从理解上SendData的执行流程应该是这样的!!
不知道你的这个流程的权威性? 是你根据自己的理解写出来的吗? 还是在某权威书籍上或者MSN等上得到的呢?
我刚才直接调用API send 呢,它的流程:什么也没有做,没有进SendProgress,没有进SendComplete
shutdown可以让端口的数据被处理完毕后才关闭端口,而其他的函数则会立即关闭端口导致数据丢失, 这句话 还是不能理解透彻呀 。
shutdown可以让端口的数据被处理完毕后才关闭端口,我查shutdown函数BAIDU里说
注意shutdown()函数并不关闭套接口,且套接口所占有的资源将被一直保持到closesocket()调用 呀; 而其他的函数则会立即关闭端口导致数据丢失,其他的函数 指什么函数了?怎么会关闭端口呢??
另外,我测试的时候,没有用shutdown函数,光用send函数,没有什么可以预见 到的危害吧?
谢谢 supergreenbean 一直来的跟贴,解疑析惑! 崇拜中 另另外,我也在尝试用WSAsend, 正在求索中 希望supergreenbean能有好消息呀
我的程序里不想发送完毕信息就关闭sckClient(ii)
所以就不用执行shutdown sckClient(ii).SocketHandle, SD_SEND 了
经过测试, 发现WSASend() 与send() 的发送效率 没有区别,纳闷中
准备 揭贴
这个函数中的-1是表示INFINITE吗?
在VC中 #define INFINITE 0xFFFFFFFF // Infinite timeout
参数也不是-1,