那么在设计客户端代码时我们主要考虑哪些问题呢?
第一是如何接收数据,往往一次传输的数据量较大,但socket一次的传输量是1024个byte,因此需要对数据在发送端进行拆分,而在接收端进行组合。
第二是需要建立缓冲区,网络传输的速度肯定比我们处理数据的速度快。
大家如果需要使用这段代码,需要编写一下其中的ClassSetup类,该类包含每个工作站的配置信息,由于版权问题,在这里就不公开了。
客户端代码如下:
Public
Class
ClassServer
#Region "参数"
' 以下是客户端到服务器端的消息开头
Const LOGININ As String = " 10 " ' 请求登陆的消息|||消息形式:10+自己的用户名
Const LOGINOUT As String = " 11 " ' 请求登出的消息|||消息形式:11+自己的用户名
Const GETULIST As String = " 12 " ' 请求获得在线用户列表|||消息形式:12+自己的用户名
Const P2PCONN As String = " 13 " ' 请求P2P连接的消息|||消息形式:13+自己的用户名+对方的用户名
Const HOLDLINE As String = " 14 " ' 保持连接.|||消息开式:14+自己的用户名
' 以下是服务器到客户端的消息开头
Const HVUSER As String = " 20 " ' 用户名已存在
Const GETUSER As String = " 21 " ' 在线用户列表|||消息格式:21+用户名+EP
Const MAKHOLD As String = " 22 " ' 打洞命令|||消息格式:22+IP
Const LOGINOK As String = " 23 " ' 登陆成功
Const SERVCLS As String = " 24 " ' 服务器关闭
Const MSGEND As String = " 25 " ' 消息结束
Const ONEOFF As String = " 26 " ' 一个客户端下线(超时下线)
Const SEARCHCLIENT As String = " 27 " ' 探测各个客户端是否存在
' 以下是客户端到客户端的消息开头
Const HOLDOK As String = " 30 " ' 打洞成功
Const CHATMSG As String = " 31 " ' 聊天消息
Const CHTMSGEND As String = " 32 " ' 聊天消息发送成功
Const GIVEMEDATA As String = " 33 " ' 添加数据订阅
Const NODATASEND As String = " 34 " ' 取消数据订阅
Const GETDEVINFO As String = " 35 " ' 获取工作站的基本信息
' 以下是工作站发送到客户端的命令:
Const RECDEVINFO As String = " 45 " ' 工作站发送给服务器的设备配置信息
Const DATA As String = " 40 " ' 表示发送的是数据信息,由工作站发送给客户端
' 以下是客户端的命名
Const EXITPRO As String = " EXIT " ' 退出命令
Const SHOWULIST As String = " SHOWUSER " ' 显示在线用户
Const HELP As String = " HELP " ' 显示帮助
Const SEND As String = " SEND " ' 发送消息
' Const OldData As String = "40"
#End Region
#Region "全局变量"
Delegate Sub myMethodDelegate( ByRef myInData As Byte ()) ' 登陆时用的事件
Dim msgSendEnd As Boolean = False ' 消息是否发送成功,若发送成功,则会返回结束消息
Dim ThListen As New Thread( AddressOf listen) ' 监听的线程
Dim ThSend As Thread = Nothing
Dim ClientSocket As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) ' 客户端套节字的定义
Public username As String ' 当前用户名
Dim ServerEP As IPEndPoint ' 服务器的IPEP
Dim holdBytes As [ Byte ]() = Encoding.Unicode.GetBytes(HOLDLINE & username) ' 和服务器保持连接连接时用到的byte数组
Dim getUrecCount As Integer
Dim testHold As Boolean = False
Dim testChat As Boolean = False
Private receiveDone As ManualResetEvent ' 在登陆时用来阻塞线程,等待收到数据
Private sendDone As ManualResetEvent ' 用来阴塞发送消息的线程.等待收到回送的确认消息
Private holdDone As ManualResetEvent ' 用来阻塞打洞时的线程
Private chatDone As ManualResetEvent ' 用来阻塞发送聊天消息时的线程
Public Connected As Boolean = True ' 用来表示是否和服务器连接成功
Dim timerDelegate As New TimerCallback( AddressOf holdonline) ' 为保持在线状态弄得
Private mytimer As Timer
Public on_off As Boolean = False ' 表示发送开关是否打开,有主任端连接即打开此开关,所有连接的主任端下线后即关闭
Public SendDataList As ArrayList
Const movelenth As Integer = 509 ' 最大为511,加上标志位为512,乘以2为传送的最大字节数:1024
Private sw As StreamWriter
Private dealing As Boolean = False
Private ReceiveDataList As DataQueue
' 此数为减去头一个标志位(表示此段是否结束:0表示未结束;1表示结束)剩余的字符长度
#End Region
#Region "方法"
Public Event SendDDIinfo( ByVal TgIP As IPEndPoint)
Public Event NetWorkError( ByVal ErrStr As String )
' 主函数,程序入口,放到splash中运行:
Sub New ()
Try
If register.Reg.GetKey( " ServerIP " ) = "" Then
ServerEP = New IPEndPoint(IPAddress.Parse( " 127.0.0.1 " ), 11000 )
Else
ServerEP = New IPEndPoint(IPAddress.Parse(register.Reg.GetKey( " ServerIP " )), 11000 ) ' 正式版本专用,从注册表读取服务器地址
End If
sw = New StreamWriter(Directory.GetCurrentDirectory & " \DataServer.log " , True )
AddHandler SendDDIinfo, AddressOf SendBasicInfo
' ********测试专用,测试版本不读注册表,本机就是服务器!********
' If getIdOfLocalhost() = "" Then
' '获取不到本机地址则退出
' RaiseEvent NetWorkError("找不到存在的连接")
' Exit Sub
' End If
' 假设本机只有一块网卡,邦定一个ip地址和端口(5555)
' 正式版从注册表中读取GUID作为名称:
' 模拟版本获取主机名为登录名称:
username = " DataServer " & Dns.GetHostName
Dim LocalEP As New IPEndPoint(IPAddress.Any, 5555 )
ClientSocket.Bind(LocalEP) ' 绑定本机端口
ReceiveDataList = New DataQueue
' 根据注册表中的ServerIp,向指定的服务器端口(11000)登录:
Dim i As Int16 = 1
While Not Login()
If i > 2 Then ' 三次登录失败,则退出循环,直接帮定本机ip的5555端口。保证可以正常通讯
Me .Connected = False
RaiseEvent NetWorkError( " 登录失败! " )
Exit While
End If
i += 1
End While
' 登陆成功后.用一个timer,每隔50秒向服务器发送消息,保持在线状态跟在主机注册的端口
mytimer = New Timer(timerDelegate, Nothing , 10000 , 50000 )
ThListen.Start()
SendDataList = New ArrayList
Catch ex As Exception
Debug.WriteLine( " Client_New: " & Err.Description)
End Try
End Sub
' 退出服务器的管理
Public Sub ExitProcess()
Try '
sw.Close()
sw = Nothing
exitApp()
ClientSocket.Close()
mytimer.Dispose()
ThListen.Abort()
Debug.WriteLine( " 成功下线! " )
Catch ex As Exception
Debug.WriteLine( " ExitProcess中报错: " & ex.Message)
End Try
End Sub
' 一个工作站登陆到服务器
Private Function Login() As Boolean
Try
receiveDone = New ManualResetEvent( False )
Dim userBytes As [ Byte ]()
Dim userOK As Boolean = False
userBytes = Encoding.Unicode.GetBytes(LOGININ & username)
' 向服务器发送客户消息
ClientSocket.SendTo(userBytes, ServerEP)
Dim data As [ Byte ]() = New Byte ( 1024 ) {}
Dim comStr As String = Encoding.Unicode.GetString(data, 0 , 4 )
' 异面的接收服务器回送的消息
Dim DGrecv As New myMethodDelegate( AddressOf recvLogin)
DGrecv.BeginInvoke(data, Nothing , Nothing )
' 等待服务器回送消息的时长为10秒,否则为服务器超时
receiveDone.WaitOne( 500 , True )
Dim recvStr As String = Encoding.Unicode.GetString(data, 0 , 4 )
If recvStr = comStr Then
Debug.WriteLine( " 服务器超时.登陆失败!! " )
Return False
End If
If Encoding.Unicode.GetString(data, 0 , 4 ) = LOGINOK Then
Debug.WriteLine( " 登陆成功!! " )
Return True
Else
Debug.WriteLine( " 服务器未知错误,登陆失败!! " )
Return False
End If
Catch ex As Exception
Debug.WriteLine( " Login: " & Err.Description)
End Try
End Function
' 解除登陆函数中的线程阻止
Sub recvLogin( ByRef inData As Byte ())
ClientSocket.Receive(inData)
receiveDone.Set()
End Sub
' 登出函数
Private Sub exitApp()
Try
Dim loginOutStr As String = LOGINOUT & username
Dim sendBytes As [ Byte ]() = Encoding.Unicode.GetBytes(loginOutStr)
ClientSocket.SendTo(sendBytes, ServerEP)
Catch ex As Exception
Debug.WriteLine( " 下线失败: " & Err.Description)
End Try
End Sub
' 客户程序监听的函数
Sub listen()
While True
Try
Dim recv As Integer = 0 ' 收到的字节数
Dim datas As [ Byte ]() = New Byte ( 1024 ) {} ' 缓冲区大小
Dim sender As New IPEndPoint(IPAddress.Any, 0 )
Dim tempRemoteEP As EndPoint = CType (sender, EndPoint)
recv = ClientSocket.ReceiveFrom(datas, tempRemoteEP) ' data存放接收到的数据,tempRemoteEP存放发送来的ip地址
Dim tmpdata As New DeclearData(datas, tempRemoteEP, recv) ' 装进信息块中
ReceiveDataList.AddItem(tmpdata) ' 将信息块装进本程序自己的缓冲区
If Not dealing Then
Dim dealdatathread As New Thread( AddressOf DealData)
dealdatathread.Name = " dealdata "
dealdatathread.Start()
End If
Catch
Debug.WriteLine( " listen: " & Err.Description)
WriteLog( " listen: " & Err.Description)
End Try
End While
End Sub
' 处理不同机器发送过来的信息
Private Sub DealData()
If Not dealing Then
dealing = True
Dim tmpmsg As DeclearData
While ReceiveDataList.count > 0
Try
tmpmsg = ReceiveDataList.GetFirstItem
Dim msgHead As String = tmpmsg.datastr.Substring( 0 , 2 )
' 可以侦听到的命令:
Debug.WriteLine( " 收到: " & tmpmsg.datastr)
If msgHead <> "" Then
Select Case msgHead
Case LOGININ
' 如果有一个节点登陆:
' 暂时不做处理
Case GIVEMEDATA ' 添加一个接收数据的监视端
If Not on_off Then
on_off = True ' 打开开关
If ThSend Is Nothing Then ' 如果此时发送数据的线程没有启动,则启动它
ThSend = New Thread( AddressOf DataMove)
ThSend.Start()
Debug.WriteLine( " 开始发送数据! " )
End If
End If
AddRss(tmpmsg.datastr, tmpmsg.fromip)
Case NODATASEND ' 取消一个接收数据的监视端
RemoveRss(tmpmsg.datastr, tmpmsg.fromip)
Case MSGEND ' 控制数据发送成功返回标志
msgSendEnd = True
sendDone.Set()
Case HOLDOK ' 保持在线信息返回
testHold = True
holdDone.Set()
Case CHTMSGEND ' 发送聊天信息返回标志
testChat = True
chatDone.Set()
Case GETDEVINFO
' 要求发送本工作站的基本信息:
SendBasicInfo(tmpmsg.fromip)
Case ONEOFF
' 某个客户端超时下线:
' 检验此信息是否为服务器正确端口发送
' 检测该客户端是否正在接收我们的数据,如果是则终止
Case SEARCHCLIENT
ReLogin(tmpmsg.fromip)
Case Else
End Select
End If
Catch ex As Exception
Debug.WriteLine( " 错误的数据: " & tmpmsg.datastr)
Debug.WriteLine( " DealData: " & Err.Description)
WriteLog( " 错误的数据: " & tmpmsg.datastr)
WriteLog( " DealData: " & Err.Description)
Finally
ReceiveDataList.Remove()
End Try
End While
dealing = False
End If
End Sub
' 一个客户端发送请求,要求本工作站向其发送数据,此请求只能由客户端发送
' 向设备实例的SendTO()数组添加该工作站的IP地址(本程序只向固定端口发送数据!)
Private Function AddRss( ByVal dt As String , ByVal ip As IPEndPoint) As Boolean
Dim i, j As Integer
Dim tmpsetup As ClassSetup
Dim flag As Boolean = False
Dim success As Boolean = False
Dim findsetup As Boolean = False
Dim id As String = dt.Substring( 2 , dt.Length - 2 )
Try
For i = 0 To DataSetUp.count - 1
tmpsetup = DataSetUp.item(i)
If id = "" Then
flag = False
For j = 0 To tmpsetup.SendTo.Length - 1
If ( Not tmpsetup.SendTo(j) Is Nothing ) AndAlso tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then
' 这个设备本来就向该客户端发送数据
flag = True
Exit For
End If
Next
If Not flag Then
j = tmpsetup.SendTo.Length
ReDim Preserve tmpsetup.SendTo(j + 1 )
tmpsetup.SendTo(j) = New IPEndPoint(ip.Address, 5556 )
End If
success = True
findsetup = True
ElseIf tmpsetup.ID = id Then ' 正是要申请的设备,进行下一步判断:
findsetup = True ' 找到了这个设备
If tmpsetup.SendTo Is Nothing Then
ReDim Preserve tmpsetup.SendTo( 1 )
tmpsetup.SendTo( 0 ) = New IPEndPoint(ip.Address, 5556 ) ' 第一个申请的客户端
success = True
Exit For ' i
Else
flag = False
For j = 0 To tmpsetup.SendTo.Length - 1
If ( Not tmpsetup.SendTo(j) Is Nothing ) AndAlso tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then ' 重复申请
Debug.WriteLine( " 该客户端已经在接收数据了!这是违法操作! " )
flag = True
Exit For ' j
End If
Next j
If Not flag Then ' 正常的申请数据
flag = False ' 检查前面是否有空的数组元素可用
For j = 0 To tmpsetup.SendTo.Length - 1
If tmpsetup.SendTo(j) Is Nothing Then ' 找到可用的
tmpsetup.SendTo(j) = New IPEndPoint(ip.Address, 5556 )
success = True
flag = True
Exit For
End If
Next j
If Not flag Then ' 没有找到可用的,重新扩展数组
j = tmpsetup.SendTo.Length
ReDim Preserve tmpsetup.SendTo(j + 1 )
tmpsetup.SendTo(j) = New IPEndPoint(ip.Address, 5556 )
success = True
End If
End If
Exit For ' i
End If
End If
Next i
If Not findsetup Then
Debug.WriteLine( " 没有找到该设备,ID信息错误! " )
End If
dt = Nothing
ip = Nothing
tmpsetup = Nothing
flag = Nothing
id = Nothing
Return success
Catch ex As Exception
Debug.WriteLine( " AddRss: " & Err.Description)
End Try
End Function
' 取消从本工作站获取数据
' 这个消息只由客户端发送
Private Function RemoveRss( ByVal dt As String , ByVal ip As IPEndPoint) As Boolean
Dim i, j As Integer
Dim tmpsetup As ClassSetup
Dim flag As Boolean = False
Dim findsetup As Boolean = False
Dim id As String = dt.Substring( 2 , dt.Length - 2 ) ' Encoding.Unicode.GetString(dt, 4, recv - 4)
For i = 0 To DataSetUp.count - 1
tmpsetup = DataSetUp.item(i)
If id = "" Then
' 该客户端下线,取消所有向此客户端的发送:
If Not tmpsetup.SendTo Is Nothing Then
For j = 0 To tmpsetup.SendTo.Length - 1
If ( Not tmpsetup.SendTo(j) Is Nothing ) AndAlso tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then
' Debug.WriteLine(tmpsetup.SendTo(j).ToString)
tmpsetup.SendTo(j) = Nothing
flag = True
findsetup = True
' Exit For
End If
Next
End If
ElseIf tmpsetup.id = id Then ' 找到该设备
findsetup = True
flag = False
For j = 0 To tmpsetup.SendTo.Length - 1
If Not tmpsetup.SendTo(j) Is Nothing Then
' Debug.WriteLine(tmpsetup.SendTo(j).ToString & ip.ToString)
If tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then ' 找到了这个客户端地址
tmpsetup.SendTo(j) = Nothing
flag = True
' Exit For 'j
End If
End If
Next
If Not flag Then ' 没有找到客户端地址
Debug.WriteLine( " 违法操作,该客户端没有申请过该工作站的数据! " )
End If
Exit For ' i
End If
Next
If Not findsetup Then
Debug.WriteLine( " 没有找到对应的设备!非法操作! " )
Return False
End If
If Not flag Then ' 没有找到客户端地址
Debug.WriteLine( " 没有找到对应的客户端地址!非法操作! " )
Return False
End If
' 检查当前是否还有客户端在接收数据:
flag = False
For i = 0 To DataSetUp.count - 1
tmpsetup = DataSetUp.item(i)
For j = 0 To tmpsetup.SendTo.Length - 1
If Not tmpsetup.SendTo(j) Is Nothing Then
' Debug.WriteLine("还有 " & tmpsetup.SendTo(j).ToString & " 在接收数据!")
flag = True ' 找到一个!
End If
Next
Next
' Debug.WriteLine("用户:" & ip.ToString & "需要取消接收数据")
' Debug.WriteLine(flag)
If Not flag Then
' 当前已经没有客户端需要本工作站发送数据了,关闭开关
on_off = False ' 关闭发送开关
Debug.WriteLine( " 关闭发送开关! " )
ThSend.Abort()
ThSend = Nothing
End If
dt = Nothing
' recv = Nothing
ip = Nothing
i = Nothing
j = Nothing
tmpsetup = Nothing
flag = Nothing
findsetup = Nothing
id = Nothing
End Function
' 用保持在线状态的函数
Private Sub holdonline( ByVal state As [ Object ])
Try
ClientSocket.SendTo(Encoding.Unicode.GetBytes(HOLDLINE & username), ServerEP)
Catch ex As Exception
Debug.WriteLine( " holdonline: " & ex.Message)
End Try
End Sub
' 用于向各个客户端发送数据,此函数通过Send线程控制:
' 这个函数只用来发送数据信息,即以40开头的信息
Public Sub DataMove()
Try
Dim data As String
Dim TempSend As String
Dim TempDev As ClassSetup
Dim i As Integer
Debug.WriteLine( " 启动发送器: " )
While on_off
Application.DoEvents()
If SendDataList.Count > 0 Then ' 如果发送的链表中有数据,则按照顺序发送:
TempDev = CType (SendDataList.Item( 0 ), ClassData).myDevice ' 获取是哪个设备要求发送的,空代表是本系统要求发送的,而不是某个设备的数据信息
data = CType (SendDataList.Item( 0 ), ClassData).mydata ' 获取数据
' 发送本数据:
For i = 0 To TempDev.SendTo.Length - 1
If Not TempDev.SendTo(i) Is Nothing Then ' 向所有需要接收本设备的客户端发送
SendLongData(data, TempDev.SendTo(i))
End If
Next
CType (SendDataList.Item( 0 ), ClassData).dispose() ' 将信息块释放掉
SendDataList.RemoveAt( 0 ) ' 删除此信息块
End If
Thread.Sleep( 100 )
End While
data = Nothing
TempSend = Nothing
Debug.WriteLine( " 发送器结束 " )
Catch ex As Exception
Debug.WriteLine( " DataMove: " & Err.Description)
End Try
End Sub
' 将一整串长数据发送到指定的ip地址:
' 格式:40+标志量+数据
Private Function SendLongData( ByVal thedata As String , ByVal ip As IPEndPoint) As Boolean
Try
Dim i As Integer
Dim head As String = thedata.Substring( 0 , 2 )
Dim TempSend As String
Dim sendbytes() As Byte
thedata = thedata.Substring( 2 , thedata.Length - 2 ) ' 获取除了数据头之外的所有数据
If thedata.Length > movelenth Then ' 第一次数据!
TempSend = head & " 0 " & thedata.Substring( 0 , movelenth) ' 添加0,表示数据的开始
thedata = thedata.Substring(movelenth, thedata.Length - movelenth) ' 将发送出去的那些字符除掉
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip) ' 发送本段信息
Thread.Sleep( 100 )
While thedata.Length > movelenth ' 如果剩下的数据大小大于可以发送的字节数,则拆分
' 发送:
TempSend = head & " 2 " & thedata.Substring( 0 , movelenth) ' 添加2,表示数据的中间部分
thedata = thedata.Substring(movelenth, thedata.Length - movelenth) ' 将发送出去的那些字符除掉
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip) ' 发送本段信息
Thread.Sleep( 100 )
End While
If thedata.Length > 0 Then ' 发送最后一段信息
TempSend = head & " 1 " & thedata ' 添加1,表示是数据的结束
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip)
Thread.Sleep( 100 )
End If
Else
TempSend = head & " 3 " & thedata ' 添加3,表示这里是全部数据一次性传送完毕
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip) ' 发送本段信息
End If
i = Nothing
head = Nothing
thedata = Nothing
ip = Nothing
TempSend = Nothing
sendbytes = Nothing
Return True
Catch ex As Exception
Debug.WriteLine( " SendLongData: " & Err.Description)
Return False
End Try
End Function
' 获取本地地址:
Private Function getIdOfLocalhost() As String
Try
Dim addressList As System.Net.IPAddress() = Dns.GetHostByName(Dns.GetHostName()).AddressList
Dim j As Integer ' 定义的循环变量j,得到本地机的ip
For j = 0 To addressList.Length - 1
If ServerEP.Address.GetAddressBytes( 0 ) = addressList(j).GetAddressBytes( 0 ) And ServerEP.Address.GetAddressBytes( 1 ) = addressList(j).GetAddressBytes( 1 ) And ServerEP.Address.GetAddressBytes( 2 ) = addressList(j).GetAddressBytes( 2 ) Then
Return addressList(j).ToString()
End If
Next j
Return ""
Catch ex As Exception
Debug.WriteLine( " getIdOfLocalhost: " & Err.Description)
End Try
End Function
' 发送本工作站的基本信息:(本函数执行的时机由接口控制,一旦出现新的设备或配置完成即执行一次)
' 如果需要发送的目标为空,则说明是发送给服务器的
' 不为空,则是发送给某个客户端的
Public Sub SendBasicInfo( Optional ByVal sendtoEP As IPEndPoint = Nothing )
Try
Dim tmpstr As String = frmShowArguments.SaveConfig( True )
Dim head As String = RECDEVINFO
Dim TempSend As String
Dim sendBytes() As Byte
Dim movelenth As Integer = 509 ' 最大为511,加上标志位为512,乘以2为传送的最大字节数:1024
' 重新组合配置文件:
If sendtoEP Is Nothing Then sendtoEP = ServerEP
While tmpstr.Length > movelenth ' 如果数据大小大于可以发送的字节数,则拆分
' 发送:
TempSend = head & " 0 " & tmpstr.Substring( 0 , movelenth) ' 添加0,表示数据未结束
tmpstr = tmpstr.Substring(movelenth, tmpstr.Length - movelenth)
sendBytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendBytes, sendtoEP)
Thread.Sleep( 100 )
End While
If tmpstr.Length > 0 Then ' 发送最后一段信息
TempSend = head & " 1 " & tmpstr
sendBytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendBytes, sendtoEP)
Thread.Sleep( 100 )
End If
Debug.WriteLine( " 向 " & sendtoEP.ToString & " 发送配置信息 " )
tmpstr = Nothing
head = Nothing
TempSend = Nothing
sendBytes = Nothing
sendtoEP = Nothing
movelenth = Nothing
Catch ex As Exception
Debug.WriteLine( " SendBasicInfo: " & Err.Description)
End Try
End Sub
' 用于回应服务器服务程序发送的探测信息
' 只是一个回应,不对服务器发回的确认成功信息做任何处理
Private Sub ReLogin( ByVal TheServerEP As IPEndPoint)
Try
Dim userBytes As [ Byte ]()
userBytes = Encoding.Unicode.GetBytes(LOGININ & username)
' 向服务器发送客户消息
ClientSocket.SendTo(userBytes, TheServerEP)
Catch ex As Exception
Debug.WriteLine( " ReLogin: " & Err.Description)
End Try
End Sub
Sub WriteLog( ByVal msg As String )
Debug.WriteLine(msg)
sw.WriteLine(msg)
sw.Flush()
End Sub
#End Region
End Class
#Region "参数"
' 以下是客户端到服务器端的消息开头
Const LOGININ As String = " 10 " ' 请求登陆的消息|||消息形式:10+自己的用户名
Const LOGINOUT As String = " 11 " ' 请求登出的消息|||消息形式:11+自己的用户名
Const GETULIST As String = " 12 " ' 请求获得在线用户列表|||消息形式:12+自己的用户名
Const P2PCONN As String = " 13 " ' 请求P2P连接的消息|||消息形式:13+自己的用户名+对方的用户名
Const HOLDLINE As String = " 14 " ' 保持连接.|||消息开式:14+自己的用户名
' 以下是服务器到客户端的消息开头
Const HVUSER As String = " 20 " ' 用户名已存在
Const GETUSER As String = " 21 " ' 在线用户列表|||消息格式:21+用户名+EP
Const MAKHOLD As String = " 22 " ' 打洞命令|||消息格式:22+IP
Const LOGINOK As String = " 23 " ' 登陆成功
Const SERVCLS As String = " 24 " ' 服务器关闭
Const MSGEND As String = " 25 " ' 消息结束
Const ONEOFF As String = " 26 " ' 一个客户端下线(超时下线)
Const SEARCHCLIENT As String = " 27 " ' 探测各个客户端是否存在
' 以下是客户端到客户端的消息开头
Const HOLDOK As String = " 30 " ' 打洞成功
Const CHATMSG As String = " 31 " ' 聊天消息
Const CHTMSGEND As String = " 32 " ' 聊天消息发送成功
Const GIVEMEDATA As String = " 33 " ' 添加数据订阅
Const NODATASEND As String = " 34 " ' 取消数据订阅
Const GETDEVINFO As String = " 35 " ' 获取工作站的基本信息
' 以下是工作站发送到客户端的命令:
Const RECDEVINFO As String = " 45 " ' 工作站发送给服务器的设备配置信息
Const DATA As String = " 40 " ' 表示发送的是数据信息,由工作站发送给客户端
' 以下是客户端的命名
Const EXITPRO As String = " EXIT " ' 退出命令
Const SHOWULIST As String = " SHOWUSER " ' 显示在线用户
Const HELP As String = " HELP " ' 显示帮助
Const SEND As String = " SEND " ' 发送消息
' Const OldData As String = "40"
#End Region
#Region "全局变量"
Delegate Sub myMethodDelegate( ByRef myInData As Byte ()) ' 登陆时用的事件
Dim msgSendEnd As Boolean = False ' 消息是否发送成功,若发送成功,则会返回结束消息
Dim ThListen As New Thread( AddressOf listen) ' 监听的线程
Dim ThSend As Thread = Nothing
Dim ClientSocket As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) ' 客户端套节字的定义
Public username As String ' 当前用户名
Dim ServerEP As IPEndPoint ' 服务器的IPEP
Dim holdBytes As [ Byte ]() = Encoding.Unicode.GetBytes(HOLDLINE & username) ' 和服务器保持连接连接时用到的byte数组
Dim getUrecCount As Integer
Dim testHold As Boolean = False
Dim testChat As Boolean = False
Private receiveDone As ManualResetEvent ' 在登陆时用来阻塞线程,等待收到数据
Private sendDone As ManualResetEvent ' 用来阴塞发送消息的线程.等待收到回送的确认消息
Private holdDone As ManualResetEvent ' 用来阻塞打洞时的线程
Private chatDone As ManualResetEvent ' 用来阻塞发送聊天消息时的线程
Public Connected As Boolean = True ' 用来表示是否和服务器连接成功
Dim timerDelegate As New TimerCallback( AddressOf holdonline) ' 为保持在线状态弄得
Private mytimer As Timer
Public on_off As Boolean = False ' 表示发送开关是否打开,有主任端连接即打开此开关,所有连接的主任端下线后即关闭
Public SendDataList As ArrayList
Const movelenth As Integer = 509 ' 最大为511,加上标志位为512,乘以2为传送的最大字节数:1024
Private sw As StreamWriter
Private dealing As Boolean = False
Private ReceiveDataList As DataQueue
' 此数为减去头一个标志位(表示此段是否结束:0表示未结束;1表示结束)剩余的字符长度
#End Region
#Region "方法"
Public Event SendDDIinfo( ByVal TgIP As IPEndPoint)
Public Event NetWorkError( ByVal ErrStr As String )
' 主函数,程序入口,放到splash中运行:
Sub New ()
Try
If register.Reg.GetKey( " ServerIP " ) = "" Then
ServerEP = New IPEndPoint(IPAddress.Parse( " 127.0.0.1 " ), 11000 )
Else
ServerEP = New IPEndPoint(IPAddress.Parse(register.Reg.GetKey( " ServerIP " )), 11000 ) ' 正式版本专用,从注册表读取服务器地址
End If
sw = New StreamWriter(Directory.GetCurrentDirectory & " \DataServer.log " , True )
AddHandler SendDDIinfo, AddressOf SendBasicInfo
' ********测试专用,测试版本不读注册表,本机就是服务器!********
' If getIdOfLocalhost() = "" Then
' '获取不到本机地址则退出
' RaiseEvent NetWorkError("找不到存在的连接")
' Exit Sub
' End If
' 假设本机只有一块网卡,邦定一个ip地址和端口(5555)
' 正式版从注册表中读取GUID作为名称:
' 模拟版本获取主机名为登录名称:
username = " DataServer " & Dns.GetHostName
Dim LocalEP As New IPEndPoint(IPAddress.Any, 5555 )
ClientSocket.Bind(LocalEP) ' 绑定本机端口
ReceiveDataList = New DataQueue
' 根据注册表中的ServerIp,向指定的服务器端口(11000)登录:
Dim i As Int16 = 1
While Not Login()
If i > 2 Then ' 三次登录失败,则退出循环,直接帮定本机ip的5555端口。保证可以正常通讯
Me .Connected = False
RaiseEvent NetWorkError( " 登录失败! " )
Exit While
End If
i += 1
End While
' 登陆成功后.用一个timer,每隔50秒向服务器发送消息,保持在线状态跟在主机注册的端口
mytimer = New Timer(timerDelegate, Nothing , 10000 , 50000 )
ThListen.Start()
SendDataList = New ArrayList
Catch ex As Exception
Debug.WriteLine( " Client_New: " & Err.Description)
End Try
End Sub
' 退出服务器的管理
Public Sub ExitProcess()
Try '
sw.Close()
sw = Nothing
exitApp()
ClientSocket.Close()
mytimer.Dispose()
ThListen.Abort()
Debug.WriteLine( " 成功下线! " )
Catch ex As Exception
Debug.WriteLine( " ExitProcess中报错: " & ex.Message)
End Try
End Sub
' 一个工作站登陆到服务器
Private Function Login() As Boolean
Try
receiveDone = New ManualResetEvent( False )
Dim userBytes As [ Byte ]()
Dim userOK As Boolean = False
userBytes = Encoding.Unicode.GetBytes(LOGININ & username)
' 向服务器发送客户消息
ClientSocket.SendTo(userBytes, ServerEP)
Dim data As [ Byte ]() = New Byte ( 1024 ) {}
Dim comStr As String = Encoding.Unicode.GetString(data, 0 , 4 )
' 异面的接收服务器回送的消息
Dim DGrecv As New myMethodDelegate( AddressOf recvLogin)
DGrecv.BeginInvoke(data, Nothing , Nothing )
' 等待服务器回送消息的时长为10秒,否则为服务器超时
receiveDone.WaitOne( 500 , True )
Dim recvStr As String = Encoding.Unicode.GetString(data, 0 , 4 )
If recvStr = comStr Then
Debug.WriteLine( " 服务器超时.登陆失败!! " )
Return False
End If
If Encoding.Unicode.GetString(data, 0 , 4 ) = LOGINOK Then
Debug.WriteLine( " 登陆成功!! " )
Return True
Else
Debug.WriteLine( " 服务器未知错误,登陆失败!! " )
Return False
End If
Catch ex As Exception
Debug.WriteLine( " Login: " & Err.Description)
End Try
End Function
' 解除登陆函数中的线程阻止
Sub recvLogin( ByRef inData As Byte ())
ClientSocket.Receive(inData)
receiveDone.Set()
End Sub
' 登出函数
Private Sub exitApp()
Try
Dim loginOutStr As String = LOGINOUT & username
Dim sendBytes As [ Byte ]() = Encoding.Unicode.GetBytes(loginOutStr)
ClientSocket.SendTo(sendBytes, ServerEP)
Catch ex As Exception
Debug.WriteLine( " 下线失败: " & Err.Description)
End Try
End Sub
' 客户程序监听的函数
Sub listen()
While True
Try
Dim recv As Integer = 0 ' 收到的字节数
Dim datas As [ Byte ]() = New Byte ( 1024 ) {} ' 缓冲区大小
Dim sender As New IPEndPoint(IPAddress.Any, 0 )
Dim tempRemoteEP As EndPoint = CType (sender, EndPoint)
recv = ClientSocket.ReceiveFrom(datas, tempRemoteEP) ' data存放接收到的数据,tempRemoteEP存放发送来的ip地址
Dim tmpdata As New DeclearData(datas, tempRemoteEP, recv) ' 装进信息块中
ReceiveDataList.AddItem(tmpdata) ' 将信息块装进本程序自己的缓冲区
If Not dealing Then
Dim dealdatathread As New Thread( AddressOf DealData)
dealdatathread.Name = " dealdata "
dealdatathread.Start()
End If
Catch
Debug.WriteLine( " listen: " & Err.Description)
WriteLog( " listen: " & Err.Description)
End Try
End While
End Sub
' 处理不同机器发送过来的信息
Private Sub DealData()
If Not dealing Then
dealing = True
Dim tmpmsg As DeclearData
While ReceiveDataList.count > 0
Try
tmpmsg = ReceiveDataList.GetFirstItem
Dim msgHead As String = tmpmsg.datastr.Substring( 0 , 2 )
' 可以侦听到的命令:
Debug.WriteLine( " 收到: " & tmpmsg.datastr)
If msgHead <> "" Then
Select Case msgHead
Case LOGININ
' 如果有一个节点登陆:
' 暂时不做处理
Case GIVEMEDATA ' 添加一个接收数据的监视端
If Not on_off Then
on_off = True ' 打开开关
If ThSend Is Nothing Then ' 如果此时发送数据的线程没有启动,则启动它
ThSend = New Thread( AddressOf DataMove)
ThSend.Start()
Debug.WriteLine( " 开始发送数据! " )
End If
End If
AddRss(tmpmsg.datastr, tmpmsg.fromip)
Case NODATASEND ' 取消一个接收数据的监视端
RemoveRss(tmpmsg.datastr, tmpmsg.fromip)
Case MSGEND ' 控制数据发送成功返回标志
msgSendEnd = True
sendDone.Set()
Case HOLDOK ' 保持在线信息返回
testHold = True
holdDone.Set()
Case CHTMSGEND ' 发送聊天信息返回标志
testChat = True
chatDone.Set()
Case GETDEVINFO
' 要求发送本工作站的基本信息:
SendBasicInfo(tmpmsg.fromip)
Case ONEOFF
' 某个客户端超时下线:
' 检验此信息是否为服务器正确端口发送
' 检测该客户端是否正在接收我们的数据,如果是则终止
Case SEARCHCLIENT
ReLogin(tmpmsg.fromip)
Case Else
End Select
End If
Catch ex As Exception
Debug.WriteLine( " 错误的数据: " & tmpmsg.datastr)
Debug.WriteLine( " DealData: " & Err.Description)
WriteLog( " 错误的数据: " & tmpmsg.datastr)
WriteLog( " DealData: " & Err.Description)
Finally
ReceiveDataList.Remove()
End Try
End While
dealing = False
End If
End Sub
' 一个客户端发送请求,要求本工作站向其发送数据,此请求只能由客户端发送
' 向设备实例的SendTO()数组添加该工作站的IP地址(本程序只向固定端口发送数据!)
Private Function AddRss( ByVal dt As String , ByVal ip As IPEndPoint) As Boolean
Dim i, j As Integer
Dim tmpsetup As ClassSetup
Dim flag As Boolean = False
Dim success As Boolean = False
Dim findsetup As Boolean = False
Dim id As String = dt.Substring( 2 , dt.Length - 2 )
Try
For i = 0 To DataSetUp.count - 1
tmpsetup = DataSetUp.item(i)
If id = "" Then
flag = False
For j = 0 To tmpsetup.SendTo.Length - 1
If ( Not tmpsetup.SendTo(j) Is Nothing ) AndAlso tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then
' 这个设备本来就向该客户端发送数据
flag = True
Exit For
End If
Next
If Not flag Then
j = tmpsetup.SendTo.Length
ReDim Preserve tmpsetup.SendTo(j + 1 )
tmpsetup.SendTo(j) = New IPEndPoint(ip.Address, 5556 )
End If
success = True
findsetup = True
ElseIf tmpsetup.ID = id Then ' 正是要申请的设备,进行下一步判断:
findsetup = True ' 找到了这个设备
If tmpsetup.SendTo Is Nothing Then
ReDim Preserve tmpsetup.SendTo( 1 )
tmpsetup.SendTo( 0 ) = New IPEndPoint(ip.Address, 5556 ) ' 第一个申请的客户端
success = True
Exit For ' i
Else
flag = False
For j = 0 To tmpsetup.SendTo.Length - 1
If ( Not tmpsetup.SendTo(j) Is Nothing ) AndAlso tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then ' 重复申请
Debug.WriteLine( " 该客户端已经在接收数据了!这是违法操作! " )
flag = True
Exit For ' j
End If
Next j
If Not flag Then ' 正常的申请数据
flag = False ' 检查前面是否有空的数组元素可用
For j = 0 To tmpsetup.SendTo.Length - 1
If tmpsetup.SendTo(j) Is Nothing Then ' 找到可用的
tmpsetup.SendTo(j) = New IPEndPoint(ip.Address, 5556 )
success = True
flag = True
Exit For
End If
Next j
If Not flag Then ' 没有找到可用的,重新扩展数组
j = tmpsetup.SendTo.Length
ReDim Preserve tmpsetup.SendTo(j + 1 )
tmpsetup.SendTo(j) = New IPEndPoint(ip.Address, 5556 )
success = True
End If
End If
Exit For ' i
End If
End If
Next i
If Not findsetup Then
Debug.WriteLine( " 没有找到该设备,ID信息错误! " )
End If
dt = Nothing
ip = Nothing
tmpsetup = Nothing
flag = Nothing
id = Nothing
Return success
Catch ex As Exception
Debug.WriteLine( " AddRss: " & Err.Description)
End Try
End Function
' 取消从本工作站获取数据
' 这个消息只由客户端发送
Private Function RemoveRss( ByVal dt As String , ByVal ip As IPEndPoint) As Boolean
Dim i, j As Integer
Dim tmpsetup As ClassSetup
Dim flag As Boolean = False
Dim findsetup As Boolean = False
Dim id As String = dt.Substring( 2 , dt.Length - 2 ) ' Encoding.Unicode.GetString(dt, 4, recv - 4)
For i = 0 To DataSetUp.count - 1
tmpsetup = DataSetUp.item(i)
If id = "" Then
' 该客户端下线,取消所有向此客户端的发送:
If Not tmpsetup.SendTo Is Nothing Then
For j = 0 To tmpsetup.SendTo.Length - 1
If ( Not tmpsetup.SendTo(j) Is Nothing ) AndAlso tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then
' Debug.WriteLine(tmpsetup.SendTo(j).ToString)
tmpsetup.SendTo(j) = Nothing
flag = True
findsetup = True
' Exit For
End If
Next
End If
ElseIf tmpsetup.id = id Then ' 找到该设备
findsetup = True
flag = False
For j = 0 To tmpsetup.SendTo.Length - 1
If Not tmpsetup.SendTo(j) Is Nothing Then
' Debug.WriteLine(tmpsetup.SendTo(j).ToString & ip.ToString)
If tmpsetup.SendTo(j).Address.ToString = ip.Address.ToString Then ' 找到了这个客户端地址
tmpsetup.SendTo(j) = Nothing
flag = True
' Exit For 'j
End If
End If
Next
If Not flag Then ' 没有找到客户端地址
Debug.WriteLine( " 违法操作,该客户端没有申请过该工作站的数据! " )
End If
Exit For ' i
End If
Next
If Not findsetup Then
Debug.WriteLine( " 没有找到对应的设备!非法操作! " )
Return False
End If
If Not flag Then ' 没有找到客户端地址
Debug.WriteLine( " 没有找到对应的客户端地址!非法操作! " )
Return False
End If
' 检查当前是否还有客户端在接收数据:
flag = False
For i = 0 To DataSetUp.count - 1
tmpsetup = DataSetUp.item(i)
For j = 0 To tmpsetup.SendTo.Length - 1
If Not tmpsetup.SendTo(j) Is Nothing Then
' Debug.WriteLine("还有 " & tmpsetup.SendTo(j).ToString & " 在接收数据!")
flag = True ' 找到一个!
End If
Next
Next
' Debug.WriteLine("用户:" & ip.ToString & "需要取消接收数据")
' Debug.WriteLine(flag)
If Not flag Then
' 当前已经没有客户端需要本工作站发送数据了,关闭开关
on_off = False ' 关闭发送开关
Debug.WriteLine( " 关闭发送开关! " )
ThSend.Abort()
ThSend = Nothing
End If
dt = Nothing
' recv = Nothing
ip = Nothing
i = Nothing
j = Nothing
tmpsetup = Nothing
flag = Nothing
findsetup = Nothing
id = Nothing
End Function
' 用保持在线状态的函数
Private Sub holdonline( ByVal state As [ Object ])
Try
ClientSocket.SendTo(Encoding.Unicode.GetBytes(HOLDLINE & username), ServerEP)
Catch ex As Exception
Debug.WriteLine( " holdonline: " & ex.Message)
End Try
End Sub
' 用于向各个客户端发送数据,此函数通过Send线程控制:
' 这个函数只用来发送数据信息,即以40开头的信息
Public Sub DataMove()
Try
Dim data As String
Dim TempSend As String
Dim TempDev As ClassSetup
Dim i As Integer
Debug.WriteLine( " 启动发送器: " )
While on_off
Application.DoEvents()
If SendDataList.Count > 0 Then ' 如果发送的链表中有数据,则按照顺序发送:
TempDev = CType (SendDataList.Item( 0 ), ClassData).myDevice ' 获取是哪个设备要求发送的,空代表是本系统要求发送的,而不是某个设备的数据信息
data = CType (SendDataList.Item( 0 ), ClassData).mydata ' 获取数据
' 发送本数据:
For i = 0 To TempDev.SendTo.Length - 1
If Not TempDev.SendTo(i) Is Nothing Then ' 向所有需要接收本设备的客户端发送
SendLongData(data, TempDev.SendTo(i))
End If
Next
CType (SendDataList.Item( 0 ), ClassData).dispose() ' 将信息块释放掉
SendDataList.RemoveAt( 0 ) ' 删除此信息块
End If
Thread.Sleep( 100 )
End While
data = Nothing
TempSend = Nothing
Debug.WriteLine( " 发送器结束 " )
Catch ex As Exception
Debug.WriteLine( " DataMove: " & Err.Description)
End Try
End Sub
' 将一整串长数据发送到指定的ip地址:
' 格式:40+标志量+数据
Private Function SendLongData( ByVal thedata As String , ByVal ip As IPEndPoint) As Boolean
Try
Dim i As Integer
Dim head As String = thedata.Substring( 0 , 2 )
Dim TempSend As String
Dim sendbytes() As Byte
thedata = thedata.Substring( 2 , thedata.Length - 2 ) ' 获取除了数据头之外的所有数据
If thedata.Length > movelenth Then ' 第一次数据!
TempSend = head & " 0 " & thedata.Substring( 0 , movelenth) ' 添加0,表示数据的开始
thedata = thedata.Substring(movelenth, thedata.Length - movelenth) ' 将发送出去的那些字符除掉
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip) ' 发送本段信息
Thread.Sleep( 100 )
While thedata.Length > movelenth ' 如果剩下的数据大小大于可以发送的字节数,则拆分
' 发送:
TempSend = head & " 2 " & thedata.Substring( 0 , movelenth) ' 添加2,表示数据的中间部分
thedata = thedata.Substring(movelenth, thedata.Length - movelenth) ' 将发送出去的那些字符除掉
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip) ' 发送本段信息
Thread.Sleep( 100 )
End While
If thedata.Length > 0 Then ' 发送最后一段信息
TempSend = head & " 1 " & thedata ' 添加1,表示是数据的结束
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip)
Thread.Sleep( 100 )
End If
Else
TempSend = head & " 3 " & thedata ' 添加3,表示这里是全部数据一次性传送完毕
sendbytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendbytes, ip) ' 发送本段信息
End If
i = Nothing
head = Nothing
thedata = Nothing
ip = Nothing
TempSend = Nothing
sendbytes = Nothing
Return True
Catch ex As Exception
Debug.WriteLine( " SendLongData: " & Err.Description)
Return False
End Try
End Function
' 获取本地地址:
Private Function getIdOfLocalhost() As String
Try
Dim addressList As System.Net.IPAddress() = Dns.GetHostByName(Dns.GetHostName()).AddressList
Dim j As Integer ' 定义的循环变量j,得到本地机的ip
For j = 0 To addressList.Length - 1
If ServerEP.Address.GetAddressBytes( 0 ) = addressList(j).GetAddressBytes( 0 ) And ServerEP.Address.GetAddressBytes( 1 ) = addressList(j).GetAddressBytes( 1 ) And ServerEP.Address.GetAddressBytes( 2 ) = addressList(j).GetAddressBytes( 2 ) Then
Return addressList(j).ToString()
End If
Next j
Return ""
Catch ex As Exception
Debug.WriteLine( " getIdOfLocalhost: " & Err.Description)
End Try
End Function
' 发送本工作站的基本信息:(本函数执行的时机由接口控制,一旦出现新的设备或配置完成即执行一次)
' 如果需要发送的目标为空,则说明是发送给服务器的
' 不为空,则是发送给某个客户端的
Public Sub SendBasicInfo( Optional ByVal sendtoEP As IPEndPoint = Nothing )
Try
Dim tmpstr As String = frmShowArguments.SaveConfig( True )
Dim head As String = RECDEVINFO
Dim TempSend As String
Dim sendBytes() As Byte
Dim movelenth As Integer = 509 ' 最大为511,加上标志位为512,乘以2为传送的最大字节数:1024
' 重新组合配置文件:
If sendtoEP Is Nothing Then sendtoEP = ServerEP
While tmpstr.Length > movelenth ' 如果数据大小大于可以发送的字节数,则拆分
' 发送:
TempSend = head & " 0 " & tmpstr.Substring( 0 , movelenth) ' 添加0,表示数据未结束
tmpstr = tmpstr.Substring(movelenth, tmpstr.Length - movelenth)
sendBytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendBytes, sendtoEP)
Thread.Sleep( 100 )
End While
If tmpstr.Length > 0 Then ' 发送最后一段信息
TempSend = head & " 1 " & tmpstr
sendBytes = Encoding.Unicode.GetBytes(TempSend)
ClientSocket.SendTo(sendBytes, sendtoEP)
Thread.Sleep( 100 )
End If
Debug.WriteLine( " 向 " & sendtoEP.ToString & " 发送配置信息 " )
tmpstr = Nothing
head = Nothing
TempSend = Nothing
sendBytes = Nothing
sendtoEP = Nothing
movelenth = Nothing
Catch ex As Exception
Debug.WriteLine( " SendBasicInfo: " & Err.Description)
End Try
End Sub
' 用于回应服务器服务程序发送的探测信息
' 只是一个回应,不对服务器发回的确认成功信息做任何处理
Private Sub ReLogin( ByVal TheServerEP As IPEndPoint)
Try
Dim userBytes As [ Byte ]()
userBytes = Encoding.Unicode.GetBytes(LOGININ & username)
' 向服务器发送客户消息
ClientSocket.SendTo(userBytes, TheServerEP)
Catch ex As Exception
Debug.WriteLine( " ReLogin: " & Err.Description)
End Try
End Sub
Sub WriteLog( ByVal msg As String )
Debug.WriteLine(msg)
sw.WriteLine(msg)
sw.Flush()
End Sub
#End Region
End Class
注:DeclearData和DataQueue两个类参见上一篇文章: .net中的socket异步通信实现--服务器端代码