讨论:浅谈winsock ConnectionRequest事件

m60a1 2009-02-26 10:16:30
加精
近期一直在研究sock编程(各种穿透代理服务器的方法),从控件级的编写到纯API的编写,在写了几个案例后,发现在使用控件编程时,二个事件的区别与费解。

在使用winsock编程时,会用到以下二个事件:Connect和ConnectionRequest
可能有朋友会说了,我在编写sock程式时并没有用到connect事件,只用了ConnectionRequest事件,达到了一样的效果(数据能够正确互通)。

Connect: 当一个 Connect 操作完成时发生。
ConnectionRequest: 当远程计算机请求连接时出现。

OK,上面是MSDN对上面二个事件的描述,仅从上面的描述来讲,只要是AB二地的通道正常打开,那么上面二个事件都将发生。

我们来举个例子(TCP为例):
A地(发起请求):

WinSock1.RemoteHost = “**.***.***.***”
WinSock1.RemotePort = 9000
WinSock1.connect

B地(响应请求):

Winsock1.LocalPort = 9000
Winsock1.Listen

调试上面的代码,你会发现仅当A地发出connect方法时,B地的ConnectionRequest事件才会进行响应

B地:
Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
‘仅当A地发出connect请求时,这里才会进行响应
dim strSend as string : strSend=”SendData”
Winsock1.Accept requestID

Do Until Winsock1.State = 7
DoEvents
Loop

Winsock1.SendData strSend
End Sub

A地:
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
‘这里接收数据
End Sub
我看过许多VB程序员用上面的代码,写winsock程式,并且这么写也可以达到他们想要的效果(数据传输)。

那么如果我说上面的发送数据方代码有问题,你肯定会用鸡蛋砸我。
不知道这么写代码的程序员,有没有想过一个问题:就是我一开始就提出的

“OK,上面是MSDN对上面二个事件的描述,仅从上面的描述来讲,只要是AB二地的通道正常打开,那么上面二个事件都将发生。”

现在AB二地的通道已经打开,那么connect事件,究竟做了点啥?是不是微软疯了,同样的功能事件,设计员设计了相同的二个???

我刚才说了上面的发送方代码有问题:发送方端容易出现死循环
上面代码中,用循环不停的测试state的状态,仅当state=7时,才会终止循环,否则一直在移交控制权。
在大规模使用winsock的情况下,服务器端sock控件往往以数组形式出现,也就是说同一个sock控件会响应来自不同客户端的请求,而每个请求,服务器在接收后,都会进行一系列的处理(此时客户端state永远不会为7),然后才会响应客户端。也就是说如果服务器端在处理某个通道的逻辑时,发现了意外,那么此时此通道的客户端代码将变成死循环,可能你会说那是你服务器端代码写的不好,跟客户端代码没关系,但对于每个有点职业道德的程序员来讲,是不能够让自己的代码出现死循环的(这里指的是所有的商业代码)

那么如果是我,我会怎么改上面的代码呢,很简单我会用connect事件,接收服务端响应

Private Sub Winsock1_Connect()
Debug.print Winsock1.State
Winsock1.SendData strSend
End Sub

在Connect事件,如果你愿意可以像我一样每次响应时,都抛出state状态,看看它的状态是什么?

上面所写,仅代表个人意见与看法,欢迎大家讨论,有不对的地方请指正,谢谢!
...全文
3152 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
沧海雪 2012-04-28
  • 打赏
  • 举报
回复
谢谢了,学习了!
qq274283104 2011-10-28
  • 打赏
  • 举报
回复
还有一种情况,就是当客户端发出连接请求,而服务器端不在,那么怎么才能够实现客户端再隔一段时间之后再发送请求,直到服务器端有响应
(这里的响应不一定要接受连接请求,总之用wskServer_ConnectionRequest事件响应不可连接都可以(因为这是服务器可能跟其他客户端连接通信中))
才结束发送连接请求
本人这在做VB连网通信实验。
希望大家能够加QQ864918769交流学习,感激!!
oshi002 2011-10-15
  • 打赏
  • 举报
回复
这个组件的用法还不知道呢。
f1305147 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 yiguangqiang88 的回复:]
同意。我的做法是这样:

Private Sub Commandlink_Click()
Form1.Commandlink.Enabled = False 'µã»÷Á´½ÓÖ®ºó£¬Ê¹µÃʧЧ
Form1.Winsock1.Connect '¿ªÊ¼Á´½Ó
End Sub

Private Sub Winsock1_Connect()
Form1.Commandsend.Enabled = True 'Á´½ÓÖ®ºóʹÄÜ·¢ËÍ
End Sub



一个connect方法,一个connect事件。
我向你伸出手,执行了一个connect方法;你看到我伸出手,就发生了ConnectionRequest事件,在这个事件可触发你决定握手(调用Accept方法)或者无视。
如果你伸出手跟我握手,双方同时完成了一个connect事件,state=7。

由于代码执行速度极快,

VB code

Winsock1.Accept requ……
[/Quote]
  • 打赏
  • 举报
回复
一个connect方法,一个connect事件。
我向你伸出手,执行了一个connect方法;你看到我伸出手,就发生了ConnectionRequest事件,在这个事件可触发你决定握手(调用Accept方法)或者无视。
如果你伸出手跟我握手,双方同时完成了一个connect事件,state=7。

由于代码执行速度极快,
Winsock1.Accept requestID
Do Until Winsock1.State = 7
DoEvents
Loop
要循环等待到它们连接成功,愚以为这种代码是不可取的。最好放在服务端的connect事件中执行。
弟弟在愤怒 2011-05-12
  • 打赏
  • 举报
回复
学习中 怎么没人讨论了
zhourien 2011-04-22
  • 打赏
  • 举报
回复
学习了,Connect: 当一个 Connect 操作完成时发生。
ConnectionRequest: 当远程计算机请求连接时出现。
很明显,有相当的差异。
都打开通道时2个都发生,没差异。但是没打开呢?
jmkang 2009-03-05
  • 打赏
  • 举报
回复
学习了!
gxj760998 2009-03-05
  • 打赏
  • 举报
回复
我接着开心海的说哈:首先异地执行了connect方法 接收方wskClient_Connect()事件不一定被会触发,
能够肯定的是会被触发wskServer_ConnectionRequest()事件,公当state=7时,connect事件才会生效(至于是不是这样请大家做海量测试,不仅仅测试本地)
支持这个观点。
linqlou 2009-03-04
  • 打赏
  • 举报
回复
好贴,希望多多探讨,我等多多受益
m60a1 2009-03-03
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 happy_sea 的回复:]
我说一下自己所理解的,有不对的地方欢迎朋友们指正:

一个典型和完整的服务端客户端程序是这样工作的:
1、服务端以约定的端口进行监听,即
wskServer.localport=123
wskServer.Listen
此时wskServer的state=2
2、客户端以约定的端口连接服务端,即
wskClient.remotehost="xxx.xxx.xxx.xxx"
wskClient.remoteport=123
wskClient.Connect
注意,只要执行Connect方法,那么无论这次连接服务端…
[/Quote]

我接着开心海的说哈:首先异地执行了connect方法 接收方wskClient_Connect()事件不一定被会触发,
能够肯定的是会被触发wskServer_ConnectionRequest()事件,公当state=7时,connect事件才会生效(至于是不是这样请大家做海量测试,不仅仅测试本地)

欢迎大家讨论这个问题:
话不说不明,理不辨不清
这是我做事的原则 见笑见笑:)
njstalk 2009-03-02
  • 打赏
  • 举报
回复
学习!
LUOLZD001 2009-03-02
  • 打赏
  • 举报
回复
学习中....
神马都能聊 2009-03-01
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 happy_sea 的回复:]
Winsock确实有很多令人费解的地方,比如我还真想不出这个Connect()事件有什么用,因为它只发生在发起连接的一端,而且不管对方是否允许,呵呵。。。
[/Quote]
既然想是握手,那么不伸,对方如何知道你的想法呢.

握手本身就是个签合同的过程.

比如,客户端是恶意的,发送数据,服务端可能会直接接收DDOS,以及大数据包等等,那么就说明了,需要先约定连接的具体规范,其中包括协议类型,端口,IP等等信息. connect就是传递这些约定和连接申请.

TCP连接你不需要BIND,而UDP则必须BIND

这与两个协议的通信方式有关,比如TCP,是连续的连接,数据传输过程中,需要反复确认传输,所以不可中间修改连接参数.而UDP没有反复的确认,所以说IP地址可以中途转换,端口为啥是独占的忘了.....所以UDP有人说速度快些,但是准确性不敢绝对保证.


PS:

不过也各有优缺点,比如TCP,确认机制并没有关于确认过程的校验,会有SYN FLOOD等.而UDP,有大包的FLOOD等.

connect这一步bugs确实很多,不是报文模仿就是畸形报文,但当初原始报文毕竟也是为了试验测试用,成也萧何败萧何...
zz005 2009-02-28
  • 打赏
  • 举报
回复
向楼主学习!
gxj760998 2009-02-28
  • 打赏
  • 举报
回复
这个东西我也不是很清楚,就看过一点TCP祥解。
我的看法是:
CONNECT是主动方在发起连接,需要根据返回才能确认是否能够建立连接
而CONNECTREQUEST是服务器方在收到客户端的连接请求后,给上层应用程序的一个事件,通过它告诉操作系统是否接受连接请求。
LZ的看法我个人认为是混淆了客户端和服务端对建立TCP的连接处理方式,因为对C++没什么了解,不对的地方请指出,多多包涵。
happy_sea 2009-02-27
  • 打赏
  • 举报
回复
我说一下自己所理解的,有不对的地方欢迎朋友们指正:

一个典型和完整的服务端客户端程序是这样工作的:
1、服务端以约定的端口进行监听,即
wskServer.localport=123
wskServer.Listen
此时wskServer的state=2
2、客户端以约定的端口连接服务端,即
wskClient.remotehost="xxx.xxx.xxx.xxx"
wskClient.remoteport=123
wskClient.Connect
注意,只要执行Connect方法,那么无论这次连接服务端如何响应,客户端都会发生wskClient_Connect()事件,而且wskClient的state会等于7
3、服务端接到客户端的连接请求,会发生wskServer_ConnectionRequest事件,在这个事件中服务端可以选择如何处理这个连接请求:
a:如果服务端对这个请求不理睬,那么本次连接失败,客户端会发生一个wskClient_close()事件,而且wskClient的state=8,必须重新close以后才能再次发起连接;而服务端wskServer的state一直是2即监听状态;
b:如果服务端要允许这次请求,那么它必须先close自己然后accept客户端的requestID,它的state会由2变为0再变为7,这时客户端和服务端才真正建立起连接。值得注意的是:服务端做Accept这个动作,在服务端和客户端不会发生任何事件,只会引起wskServer的state的改变!
4、连接建立后,就可以相互发送数据了,任何一端SendData后会发生一个SendComplete事件,而接到数据的一端会发生一个DataArrival事件,在该事件中用getdata取出数据进行处理就行了;
5、任务完成后,任何一端都可以用close方法来结束这次连接,比如客户端wskClient.close,那么它会发生wskClient_Close()事件,state会由7变成0,服务端也会同时发生wskServer_close()事件,但是它的state则会由7变为8,它必须close以后重新进行监听,等待客户端的再次连接。

以上就是一次完整连接的过程,可以看出来,之所以有很多人选择在ConnectionRequest()事件中作出响应并发送数据,基本上是没有更好的办法的,比如说一个聊天程序,客户端上线后服务端需要发送一句友好的问候语,那么你怎么办?选择只有ConnectionRequest()事件!

Winsock确实有很多令人费解的地方,比如我还真想不出这个Connect()事件有什么用,因为它只发生在发起连接的一端,而且不管对方是否允许,呵呵。。。
jhone99 2009-02-26
  • 打赏
  • 举报
回复
学习
m60a1 2009-02-26
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 happy_sea 的回复:]
每个事件都有它自己的作用,对于一次连接过程来说,Connect和ConnectionRequest事件只是发生在连接之初的,连接成功后就不会再发生了。
而DataArrival是发生在每次接收到数据时,A发送,到达B处,那么B就会发生DataArrival;B发送,到达A处,那么A就会发生DataArrival。
而那个ConnectionRequest,是在连接还没建立前,一方发出连接请求,另一方发生ConnectionRequest,它只会发生在被请求的一方。
不明白楼主怎么会对这几…
[/Quote]

上面说的没有错,但我只是对许多程序员这种编写方式提出致疑罢了,即然ConnectionRequest是在连接前发生的,那么就不应该把发送写在这里面,而大多数程序员都喜欢把发送写在这个事件里面,,,我只是针对这一问题,提出自己的看法 :)
m60a1 2009-02-26
  • 打赏
  • 举报
回复
说的,就是连接之初的问题,连接上了就没它俩什么事了 :)
加载更多回复(12)

7,762

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧