我用vb做客户端,winsock数组做中间层,access做数据库。现在问题是这样,客户端用winsock向服务器上的winsock发送ckIP查询命令,服务器上的winsock(0)监听,然后动态生成数组并接收客户端的ckIP命令,然后调用ckIP_sub过程,ckIP_sub查询数据库,再将查询的结果返回给服务器上的winsock(数组),然后服务器上的winsock(数组)再返回给客户端winsock。
出现的问题是,在服务器端收到ckIP命令,并调用ckIP_sub过程查询数据库的过程中,如果有另一个客户端b登陆的话,那么ckIP_sub查询的结果就会被返回到这个最后登陆的客户端b上,请问是怎么回事?
下面是相关部代的代码:客户端发送命令的代码:
'发送数据
Private Sub SendDate()
Dim cinfo
cinfo = "请求检查客户端IP"
sock.SendData cinfo
StateInfo.Caption = "正在向服务器请求验证IP..."
End Sub服务器端接收命令并调用ckIP_sub过程的代码:
'接收用户数据并根据信息字符串来判断是什么命令而调用相关的过程
Public Sub Sock_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim cinfo As String
Dim svrinfo As String
Text1.Text = "数据来自序列:" & Index & ", IP:" & Sock(Index).RemoteHostIP
Sock(Index).GetData cinfo '取得客户端发送的信息
If cinfo = "请求检查客户端IP" Then '判断是什么命令
Text1.Text = "客户端请求检查用户:" & Index & ",的IP:" & Sock(Index).RemoteHostIP & "是否合法"
Call ckIP_Sub '调用模块中的IP检测过程
End If
End Sub模块中ckIP_sub的代码:
Public Sub ckIP_Sub() '查询语句
Call LinkDB_Sub
rs.Open "select * from ipusers where ipaddress='" & Form1.Sock(Index).RemoteHostIP & "'", cn
If Not rs.EOF Then
ckIP_res = True
svrinfo = ckIP_res
MsgBox svrinfo
Form1.Sock(Index).SendData svrinfo
Form1.Text1.Text = "已返回数据至用户:" & Index & ", IP:" & Form1.Sock(Index).RemoteHostIP
Else
ckIP_res = False
svrinfo = ckIP_res
MsgBox svrinfo
Form1.Sock(Index).SendData svrinfo
Form1.Text1.Text = "已返回数据至用户:" & Index & ", IP:" & Form1.Sock(Index).RemoteHostIP
End If
'Form1.Label1.Caption = rs.GetString
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
请问上面代码中,是哪个地方造成服务器将查询结果发送到了最后登陆的客户端上?
出现的问题是,在服务器端收到ckIP命令,并调用ckIP_sub过程查询数据库的过程中,如果有另一个客户端b登陆的话,那么ckIP_sub查询的结果就会被返回到这个最后登陆的客户端b上,请问是怎么回事?
下面是相关部代的代码:客户端发送命令的代码:
'发送数据
Private Sub SendDate()
Dim cinfo
cinfo = "请求检查客户端IP"
sock.SendData cinfo
StateInfo.Caption = "正在向服务器请求验证IP..."
End Sub服务器端接收命令并调用ckIP_sub过程的代码:
'接收用户数据并根据信息字符串来判断是什么命令而调用相关的过程
Public Sub Sock_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim cinfo As String
Dim svrinfo As String
Text1.Text = "数据来自序列:" & Index & ", IP:" & Sock(Index).RemoteHostIP
Sock(Index).GetData cinfo '取得客户端发送的信息
If cinfo = "请求检查客户端IP" Then '判断是什么命令
Text1.Text = "客户端请求检查用户:" & Index & ",的IP:" & Sock(Index).RemoteHostIP & "是否合法"
Call ckIP_Sub '调用模块中的IP检测过程
End If
End Sub模块中ckIP_sub的代码:
Public Sub ckIP_Sub() '查询语句
Call LinkDB_Sub
rs.Open "select * from ipusers where ipaddress='" & Form1.Sock(Index).RemoteHostIP & "'", cn
If Not rs.EOF Then
ckIP_res = True
svrinfo = ckIP_res
MsgBox svrinfo
Form1.Sock(Index).SendData svrinfo
Form1.Text1.Text = "已返回数据至用户:" & Index & ", IP:" & Form1.Sock(Index).RemoteHostIP
Else
ckIP_res = False
svrinfo = ckIP_res
MsgBox svrinfo
Form1.Sock(Index).SendData svrinfo
Form1.Text1.Text = "已返回数据至用户:" & Index & ", IP:" & Form1.Sock(Index).RemoteHostIP
End If
'Form1.Label1.Caption = rs.GetString
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
请问上面代码中,是哪个地方造成服务器将查询结果发送到了最后登陆的客户端上?
Private Sub ServerSock_ConnectionRequest(Index As Integer, ByVal requestID As Long)
On Error Resume Next
UserIp = ServerSock(0).RemoteHostIP '获得登录者的IP地址
i = 1
Do While i <= ServerSock.UBound '检查是否已经有该地址的记录
If ServerSock(i).RemoteHostIP = UserIp Then '如有,不必加载新的控件
ServerSock(i).Accept requestID
Exit Sub
End If
i = i + 1
Loop
'如果还没有此IP的连接成功记录,在这里先建立连接再判断是否是合法IP!
'不是的话 再退出这个过程,不接受这个requestID,
'################################################################
'以下代码是你的,没细看要, 想实现返回提示错误信息应该是先Accept requestID,发送错误提示信息,再关闭此连接吧
'是的话
Load ServerSock(i)
ServerSock(i).Accept requestID
End Sub
2、你的这样三层结构,我还是有点担心,你可以向服务器发送sql语句,但返回的rs记录集,你的中间层怎么处理发送,你的应用层怎么实现获取记录集。
1.设定端口号、开始侦听 2.接收客户连接请求
3.接收、发送数据 4.响应客户关闭、主动关闭连接
设定端口号、开始侦听
我们可以使用控件数组创建多客户服务器,达到多个客户同时连接到服务器。
向窗体增加一个WinSock控件,修改其Name属性为SockServer,修改Index属性为0。
在窗体的Load事件中增加如下代码:
SockServer(0).LocalPort=2000
SockServer(0).Listen
数组控件0始终处于侦听状态。
接收客户连接请求
在ConnectionRequest事件中首先加载一个Socket控件,再用它来接收连接。
Dim SockNum As Integer
SockNum=0
Sub SockServer_ConnectionRequest(...)
SockNum=SockNum+1
Load SockServer(SockNum)
SockServer(SockNum).Accept requestID
End Sub
接收客户发送的数据 和 向客户发送的数据
接收客户发送的数据
在DataArrival事件中将多一个Index参数,用于表示哪一个控件接收到了数据。
Sub SockServer_DataArrival(Index As Integer,ByVal bytesTotal As Long)
Dim s As String
SockServer(Index).GetData s
End Sub
向客户发送的数据
哪一个控件需要发送,只需加上数组下标。
SockServer(n).SendData Text1.Text
响应客户关闭 和 主动关闭连接
响应客户关闭
同样在Close事件中也会增加Index参数表示哪一个连接关闭。
Sub SockServer_Close(Index As Integer)
SockServer(Index).Close
End Sub
主动关闭连接
哪一个连接需要主动关闭,只需增加数组下标。
SockServer(n).Close
当server端对A的请求没有完成时,其他client发来的消息都应该进入到队列中等候;当server端对A的请求处理完成时,因该到消息队列中得到下一个处理任务(即排在A机器后的请求或是优先级别高的请求),如此循环处理消息队列中的任务,直到空为止。这样才能明确你的处理逻辑,否则过于混乱,不利于维护。
队列可以用数组或是collection来维护,循环访问队列可以用timer来实现。
以上仅供参考。:)
可以设置一个参数sckindex为全局变量
sock(sckindex)这样sckindex可以在下面的过程使用