使用VB的Winsock控件,完成公司一个小Demo。
期间遇到很多问题,此处整理如下
一. winsock控件的用法
添加控件: 工程-部件- Microsoft Winsock Control 6.0
拖一个控件出来命名为winsock1
做客户端时:
winsock1.RemoteHost = "127.0.0.1"'目标服务器的IP地址,(此处测试用本地IP) winsock1.RemotePort = 15555'目标服务器的指定端口号 winsock1.Connect '连接 在winsock1_Connect事件中发送数据 winsock1.SendData (strdata)‘发送字符串数据
做服务器端时:(主要用来监听客户端通过端口发过来的数据)
流程:设定监听--接收请求连接并发送连接ID--接收数据--继续监听
winsock1.LocalPort = 15555 '设定监听端口 winsock1.Listen '开启监听 在winsock1_ConnectionRequest(ByVal requestID As Long) 事件中做如下处理 winsock1.Accept requestID'对客户端的连接请求做回应 在winsock1_DataArrival(ByVal bytesTotal As Long)事件中处理接收到的数据 '该事件为winsock控件接收到缓存数据并通知客户的功用,bytesTotal为缓存数据长度,获取数据用GetData()函数 winsock1.GetData strdata‘以字符串格式接收具体数据 '继续监听前需做关闭处理,因为winsock控件处于监听状态时,该控件接收一次数据后,自动转为连接状态,此时不再有监听功能 '故此处续作如下处理 If winsock1.State <> sckClosed Then winsock1.Close'通过连接状态判断连接情况,关闭控件 winsock1.Listen '重新开启监听
二. 服务器端处理(本项目主要是服务器端需求,客户端不再分析处理,可参考)
需求:1. 接收客户端每4s发送一次的连接请求 2. 发送一个确认连接二进制字符 3. 开始长连接接收数据
1. 客户端的4s请求接收,按照第一部分标题处理服务器端的操作,出问题了。服务器会持续不断的接收到请求数据,并不停的刷数据。
经多方查找总算找到解决方案了:生成两个控件sckListen、sckServer,一个用于监听一个用于接收数据。这种情况下监听的winsock控件状态一直为监听状态不会断开也不会改变,sckServer用于接收数据并用于以后的长连接等等功用。
实现如下:
sckListen.LocalPort = 15555 ‘设定监听端口 sckListen.Listen '开启监听 在sckListen_ConnectionRequest(ByVal requestID As Long) 事件中做如下处理 sckServer.Accept requestID '对客户端的连接请求做回应【此处请求用sckServer回应】 在sckServer_DataArrival(ByVal bytesTotal As Long)事件中处理接收到的数据 sckServer.GetData strdata‘以字符串格式接收具体数据及此如上需求的第一个问题就实现了,sckListen每个4s监听到一条数据请求,由sckServer回复请求连接,再接收数据,处理即结束。
2. 发送一段二进制字符 主要难点在二进制字符的生成及转化上,以及winsock发送二进制数据的方式
'十六进制字符串转byte()形式 Function HexToByte(str As String) As Byte() Dim rst() As Byte Dim i As Long,j As Long i = Len(str) j = i \ 2 - 1 ReDim rst(j) For i = 0 To j rst(i) = CByte("&H" & Mid$(str,i + i + 1,2)) Next HexToByte = rst() End Function使用过程如下
Dim RequestYES() As Byte RequestYES = HexToByte("00400F000000000000000000") For i = 0 To UBound(RequestYES) - LBound(RequestYES) sckServer.SendData RequestYES(i) Next使用sckServer发送二进制数据,建立长连接。
3. 长连接数据接收部分
长连接在建立之后开始持续接收。此时监听控件sckListen就收不到监听请求连接了。此时的长连接数据就在sckServer的sckServer_DataArrival事件中进行接收处理。
此处项目的主要难点是接收到的数据包,包含4字节的OrderID以及4字节的数据长度。此处就需要编写数据截取以及byte数据转化的情况了。
如下方式接收byte数组数据:
Dim bytedata() As Byte sckServer.GetData bytedata()byte数组截取实现:
'byte()数组赋值问题 Public Function CopyArrayBytes(bits() As Byte,pos As Integer,count As Long) As Byte() Dim Res() As Byte Dim i As Integer Dim j As Integer Dim iend As Integer iend = UBound(bits) - LBound(bits) + 1 iend = IIf(iend < (pos + count),iend,pos + count) ReDim Res(iend - 1 - pos) j = 0 For i = pos To (iend - 1) Res(j) = bits(i) j = j + 1 Next CopyArrayBytes = Res End Functionbyte数组数据转化:
'十六进制字符串转byte()形式 Function HexToByte(str As String) As Byte() Dim rst() As Byte Dim i As Long,2)) Next HexToByte = rst() End Function4位字节转整形数据:(此处源数据为小端输出,如为小端模式则反向转换)
'4位byte值转int型值 Function ByteToInteger(bits() As Byte) As Long Dim x As Long x = CLng(bits(0)) + CLng(bits(1)) * 256 + CLng(bits(2)) * 65536 + CLng(bits(3)) * 16777216 ByteToInteger = x End Function
'byte()转十六进制string形式 Public Function BytesToHex(bits() As Byte) As String Dim i As Long Dim b Dim s As String For Each b In bits If b < 16 Then s = s & "0" & Hex(b) Else s = s & Hex(b) End If Next BytesToHex = s End Function
三、最后说明一些边角问题
1. 本程序仅用于Demo,故只做了一个客户端的连接及监控,如需做多客户端的,需在sckListen_ConnectionRequest(ByVal requestID As Long)事件中加载多客户端控件,然后分配连接。改代码框架可百度自行搜索。