.net中的socket异步通信实现--客户端代码
生活随笔
收集整理的這篇文章主要介紹了
.net中的socket异步通信实现--客户端代码
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在上一篇文章中主要介紹了socket異步通信實(shí)現(xiàn)的服務(wù)器端代碼,下面我們來分析一下客戶端代碼:
那么在設(shè)計(jì)客戶端代碼時(shí)我們主要考慮哪些問題呢?
第一是如何接收數(shù)據(jù),往往一次傳輸?shù)臄?shù)據(jù)量較大,但socket一次的傳輸量是1024個(gè)byte,因此需要對(duì)數(shù)據(jù)在發(fā)送端進(jìn)行拆分,而在接收端進(jìn)行組合。
第二是需要建立緩沖區(qū),網(wǎng)絡(luò)傳輸?shù)乃俣瓤隙ū任覀兲幚頂?shù)據(jù)的速度快。
大家如果需要使用這段代碼,需要編寫一下其中的ClassSetup類,該類包含每個(gè)工作站的配置信息,由于版權(quán)問題,在這里就不公開了。
客戶端代碼如下:
Public?Class?ClassServer
#Region?"參數(shù)"
????'以下是客戶端到服務(wù)器端的消息開頭?
????Const?LOGININ?As?String?=?"10"?'請(qǐng)求登陸的消息|||消息形式:10+自己的用戶名?
????Const?LOGINOUT?As?String?=?"11"?'請(qǐng)求登出的消息|||消息形式:11+自己的用戶名?
????Const?GETULIST?As?String?=?"12"?'請(qǐng)求獲得在線用戶列表|||消息形式:12+自己的用戶名?
????Const?P2PCONN?As?String?=?"13"?'請(qǐng)求P2P連接的消息|||消息形式:13+自己的用戶名+對(duì)方的用戶名?
????Const?HOLDLINE?As?String?=?"14"?'保持連接.|||消息開式:14+自己的用戶名?
????'以下是服務(wù)器到客戶端的消息開頭?
????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"?'服務(wù)器關(guān)閉?
????Const?MSGEND?As?String?=?"25"?'消息結(jié)束?
????Const?ONEOFF?As?String?=?"26"?'一個(gè)客戶端下線(超時(shí)下線)
????Const?SEARCHCLIENT?As?String?=?"27"?'探測(cè)各個(gè)客戶端是否存在
????'以下是客戶端到客戶端的消息開頭?
????Const?HOLDOK?As?String?=?"30"?'打洞成功?
????Const?CHATMSG?As?String?=?"31"?'聊天消息?
????Const?CHTMSGEND?As?String?=?"32"?'聊天消息發(fā)送成功?
????Const?GIVEMEDATA?As?String?=?"33"?'添加數(shù)據(jù)訂閱
????Const?NODATASEND?As?String?=?"34"?'取消數(shù)據(jù)訂閱
????Const?GETDEVINFO?As?String?=?"35"?'獲取工作站的基本信息
????'以下是工作站發(fā)送到客戶端的命令:
????Const?RECDEVINFO?As?String?=?"45"?'工作站發(fā)送給服務(wù)器的設(shè)備配置信息
????Const?DATA?As?String?=?"40"???????'表示發(fā)送的是數(shù)據(jù)信息,由工作站發(fā)送給客戶端
????'以下是客戶端的命名?
????Const?EXITPRO?As?String?=?"EXIT"?'退出命令?
????Const?SHOWULIST?As?String?=?"SHOWUSER"?'顯示在線用戶?
????Const?HELP?As?String?=?"HELP"?'顯示幫助?
????Const?SEND?As?String?=?"SEND"?'發(fā)送消息?
????'Const?OldData?As?String?=?"40"
#End?Region
#Region?"全局變量"
????Delegate?Sub?myMethodDelegate(ByRef?myInData?As?Byte())?'登陸時(shí)用的事件?
????Dim?msgSendEnd?As?Boolean?=?False?'消息是否發(fā)送成功,若發(fā)送成功,則會(huì)返回結(jié)束消息?
????Dim?ThListen?As?New?Thread(AddressOf?listen)?'監(jiān)聽的線程?
????Dim?ThSend?As?Thread?=?Nothing
????Dim?ClientSocket?As?New?Socket(AddressFamily.InterNetwork,?SocketType.Dgram,?ProtocolType.Udp)?'客戶端套節(jié)字的定義?
????Public?username?As?String?'當(dāng)前用戶名?
????Dim?ServerEP?As?IPEndPoint?'服務(wù)器的IPEP?
????Dim?holdBytes?As?[Byte]()?=?Encoding.Unicode.GetBytes(HOLDLINE?&?username)?'和服務(wù)器保持連接連接時(shí)用到的byte數(shù)組?
????Dim?getUrecCount?As?Integer
????Dim?testHold?As?Boolean?=?False
????Dim?testChat?As?Boolean?=?False
????Private?receiveDone?As?ManualResetEvent?'在登陸時(shí)用來阻塞線程,等待收到數(shù)據(jù)?
????Private?sendDone?As?ManualResetEvent?'用來陰塞發(fā)送消息的線程.等待收到回送的確認(rèn)消息??
????Private?holdDone?As?ManualResetEvent?'用來阻塞打洞時(shí)的線程?
????Private?chatDone?As?ManualResetEvent?'用來阻塞發(fā)送聊天消息時(shí)的線程?
????Public?Connected?As?Boolean?=?True???'用來表示是否和服務(wù)器連接成功
????Dim?timerDelegate?As?New?TimerCallback(AddressOf?holdonline)?'為保持在線狀態(tài)弄得?
????Private?mytimer?As?Timer
????Public?on_off?As?Boolean?=?False????'表示發(fā)送開關(guān)是否打開,有主任端連接即打開此開關(guān),所有連接的主任端下線后即關(guān)閉
????Public?SendDataList?As?ArrayList
????Const?movelenth?As?Integer?=?509?'最大為511,加上標(biāo)志位為512,乘以2為傳送的最大字節(jié)數(shù):1024
????Private?sw?As?StreamWriter
????Private?dealing?As?Boolean?=?False
????Private?ReceiveDataList?As?DataQueue
????'此數(shù)為減去頭一個(gè)標(biāo)志位(表示此段是否結(jié)束:0表示未結(jié)束;1表示結(jié)束)剩余的字符長(zhǎng)度
#End?Region
#Region?"方法"
????Public?Event?SendDDIinfo(ByVal?TgIP?As?IPEndPoint)
????Public?Event?NetWorkError(ByVal?ErrStr?As?String)
????'主函數(shù),程序入口,放到splash中運(yùn)行:?
????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)??'正式版本專用,從注冊(cè)表讀取服務(wù)器地址
????????????End?If
????????????sw?=?New?StreamWriter(Directory.GetCurrentDirectory?&?"\DataServer.log",?True)
????????????AddHandler?SendDDIinfo,?AddressOf?SendBasicInfo
????????????'********測(cè)試專用,測(cè)試版本不讀注冊(cè)表,本機(jī)就是服務(wù)器!********
????????????'If?getIdOfLocalhost()?=?""?Then
????????????'????'獲取不到本機(jī)地址則退出
????????????'????RaiseEvent?NetWorkError("找不到存在的連接")
????????????'????Exit?Sub
????????????'End?If
????????????'假設(shè)本機(jī)只有一塊網(wǎng)卡,邦定一個(gè)ip地址和端口(5555)
????????????'正式版從注冊(cè)表中讀取GUID作為名稱:
????????????'模擬版本獲取主機(jī)名為登錄名稱:
????????????username?=?"DataServer?"?&?Dns.GetHostName
????????????Dim?LocalEP?As?New?IPEndPoint(IPAddress.Any,?5555)
????????????ClientSocket.Bind(LocalEP)??????'綁定本機(jī)端口
????????????ReceiveDataList?=?New?DataQueue
????????????'根據(jù)注冊(cè)表中的ServerIp,向指定的服務(wù)器端口(11000)登錄:
????????????Dim?i?As?Int16?=?1
????????????While?Not?Login()
????????????????If?i?>?2?Then??????'三次登錄失敗,則退出循環(huán),直接幫定本機(jī)ip的5555端口。保證可以正常通訊
????????????????????Me.Connected?=?False
????????????????????RaiseEvent?NetWorkError("登錄失敗!")
????????????????????Exit?While
????????????????End?If
????????????????i?+=?1
????????????End?While
????????????'登陸成功后.用一個(gè)timer,每隔50秒向服務(wù)器發(fā)送消息,保持在線狀態(tài)跟在主機(jī)注冊(cè)的端口?
????????????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
????'退出服務(wù)器的管理
????Public?Sub?ExitProcess()
????????Try?'
????????????sw.Close()
????????????sw?=?Nothing
????????????exitApp()
????????????ClientSocket.Close()
????????????mytimer.Dispose()
????????????ThListen.Abort()
????????????Debug.WriteLine("成功下線!")
????????Catch?ex?As?Exception
????????????Debug.WriteLine("ExitProcess中報(bào)錯(cuò):"?&?ex.Message)
????????End?Try
????End?Sub
????'一個(gè)工作站登陸到服務(wù)器
????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)
????????????'向服務(wù)器發(fā)送客戶消息?
????????????ClientSocket.SendTo(userBytes,?ServerEP)
????????????Dim?data?As?[Byte]()?=?New?Byte(1024)?{}
????????????Dim?comStr?As?String?=?Encoding.Unicode.GetString(data,?0,?4)
????????????'異面的接收服務(wù)器回送的消息?
????????????Dim?DGrecv?As?New?myMethodDelegate(AddressOf?recvLogin)
????????????DGrecv.BeginInvoke(data,?Nothing,?Nothing)
????????????'等待服務(wù)器回送消息的時(shí)長(zhǎng)為10秒,否則為服務(wù)器超時(shí)?
????????????receiveDone.WaitOne(500,?True)
????????????Dim?recvStr?As?String?=?Encoding.Unicode.GetString(data,?0,?4)
????????????If?recvStr?=?comStr?Then
????????????????Debug.WriteLine("服務(wù)器超時(shí).登陸失敗!!")
????????????????Return?False
????????????End?If
????????????If?Encoding.Unicode.GetString(data,?0,?4)?=?LOGINOK?Then
????????????????Debug.WriteLine("登陸成功!!")
????????????????Return?True
????????????Else
????????????????Debug.WriteLine("服務(wù)器未知錯(cuò)誤,登陸失敗!!")
????????????????Return?False
????????????End?If
????????Catch?ex?As?Exception
????????????Debug.WriteLine("Login:"?&?Err.Description)
????????End?Try
????End?Function
????'解除登陸函數(shù)中的線程阻止
????Sub?recvLogin(ByRef?inData?As?Byte())
????????ClientSocket.Receive(inData)
????????receiveDone.Set()
????End?Sub
????'登出函數(shù)?
????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
????'客戶程序監(jiān)聽的函數(shù)?
????Sub?listen()
????????While?True
????????????Try
????????????????Dim?recv?As?Integer?=?0?'收到的字節(jié)數(shù)?
????????????????Dim?datas?As?[Byte]()?=?New?Byte(1024)?{}?'緩沖區(qū)大小?
????????????????Dim?sender?As?New?IPEndPoint(IPAddress.Any,?0)
????????????????Dim?tempRemoteEP?As?EndPoint?=?CType(sender,?EndPoint)
????????????????recv?=?ClientSocket.ReceiveFrom(datas,?tempRemoteEP)??????'data存放接收到的數(shù)據(jù),tempRemoteEP存放發(fā)送來的ip地址
????????????????Dim?tmpdata?As?New?DeclearData(datas,?tempRemoteEP,?recv)????'裝進(jìn)信息塊中
????????????????ReceiveDataList.AddItem(tmpdata)????????????????????????????'將信息塊裝進(jìn)本程序自己的緩沖區(qū)
????????????????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
????'處理不同機(jī)器發(fā)送過來的信息
????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
????????????????????????????????'如果有一個(gè)節(jié)點(diǎn)登陸:
????????????????????????????????'暫時(shí)不做處理
????????????????????????????Case?GIVEMEDATA?????????'添加一個(gè)接收數(shù)據(jù)的監(jiān)視端
????????????????????????????????If?Not?on_off?Then
????????????????????????????????????on_off?=?True???????'打開開關(guān)
????????????????????????????????????If?ThSend?Is?Nothing?Then???'如果此時(shí)發(fā)送數(shù)據(jù)的線程沒有啟動(dòng),則啟動(dòng)它
????????????????????????????????????????ThSend?=?New?Thread(AddressOf?DataMove)
????????????????????????????????????????ThSend.Start()
????????????????????????????????????????Debug.WriteLine("開始發(fā)送數(shù)據(jù)!")
????????????????????????????????????End?If
????????????????????????????????End?If
????????????????????????????????AddRss(tmpmsg.datastr,?tmpmsg.fromip)
????????????????????????????Case?NODATASEND?????????'取消一個(gè)接收數(shù)據(jù)的監(jiān)視端
????????????????????????????????RemoveRss(tmpmsg.datastr,?tmpmsg.fromip)
????????????????????????????Case?MSGEND?????????????'控制數(shù)據(jù)發(fā)送成功返回標(biāo)志
????????????????????????????????msgSendEnd?=?True
????????????????????????????????sendDone.Set()
????????????????????????????Case?HOLDOK?????????????'保持在線信息返回
????????????????????????????????testHold?=?True
????????????????????????????????holdDone.Set()
????????????????????????????Case?CHTMSGEND??????????'發(fā)送聊天信息返回標(biāo)志
????????????????????????????????testChat?=?True
????????????????????????????????chatDone.Set()
????????????????????????????Case?GETDEVINFO
????????????????????????????????'要求發(fā)送本工作站的基本信息:
????????????????????????????????SendBasicInfo(tmpmsg.fromip)
????????????????????????????Case?ONEOFF
????????????????????????????????'某個(gè)客戶端超時(shí)下線:
????????????????????????????????'檢驗(yàn)此信息是否為服務(wù)器正確端口發(fā)送
????????????????????????????????'檢測(cè)該客戶端是否正在接收我們的數(shù)據(jù),如果是則終止
????????????????????????????Case?SEARCHCLIENT
????????????????????????????????ReLogin(tmpmsg.fromip)
????????????????????????????Case?Else
????????????????????????End?Select
????????????????????End?If
????????????????Catch?ex?As?Exception
????????????????????Debug.WriteLine("錯(cuò)誤的數(shù)據(jù):"?&?tmpmsg.datastr)
????????????????????Debug.WriteLine("DealData:"?&?Err.Description)
????????????????????WriteLog("錯(cuò)誤的數(shù)據(jù):"?&?tmpmsg.datastr)
????????????????????WriteLog("DealData:"?&?Err.Description)
????????????????Finally
????????????????????ReceiveDataList.Remove()
????????????????End?Try
????????????End?While
????????????dealing?=?False
????????End?If
????End?Sub
????'一個(gè)客戶端發(fā)送請(qǐng)求,要求本工作站向其發(fā)送數(shù)據(jù),此請(qǐng)求只能由客戶端發(fā)送
????'向設(shè)備實(shí)例的SendTO()數(shù)組添加該工作站的IP地址(本程序只向固定端口發(fā)送數(shù)據(jù)!)
????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
????????????????????????????'這個(gè)設(shè)備本來就向該客戶端發(fā)送數(shù)據(jù)
????????????????????????????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??????????'正是要申請(qǐng)的設(shè)備,進(jìn)行下一步判斷:
????????????????????findsetup?=?True????'找到了這個(gè)設(shè)備
????????????????????If?tmpsetup.SendTo?Is?Nothing?Then
????????????????????????ReDim?Preserve?tmpsetup.SendTo(1)
????????????????????????tmpsetup.SendTo(0)?=?New?IPEndPoint(ip.Address,?5556)???????????'第一個(gè)申請(qǐng)的客戶端
????????????????????????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???'重復(fù)申請(qǐng)
????????????????????????????????Debug.WriteLine("該客戶端已經(jīng)在接收數(shù)據(jù)了!這是違法操作!")
????????????????????????????????flag?=?True
????????????????????????????????Exit?For????'j
????????????????????????????End?If
????????????????????????Next?j
????????????????????????If?Not?flag?Then????????'正常的申請(qǐng)數(shù)據(jù)
????????????????????????????flag?=?False????????'檢查前面是否有空的數(shù)組元素可用
????????????????????????????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????'沒有找到可用的,重新擴(kuò)展數(shù)組
????????????????????????????????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("沒有找到該設(shè)備,ID信息錯(cuò)誤!")
????????????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
????'取消從本工作站獲取數(shù)據(jù)
????'這個(gè)消息只由客戶端發(fā)送
????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
????????????????'該客戶端下線,取消所有向此客戶端的發(fā)送:
????????????????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??????'找到該設(shè)備
????????????????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???????'找到了這個(gè)客戶端地址
????????????????????????????tmpsetup.SendTo(j)?=?Nothing
????????????????????????????flag?=?True
????????????????????????????'Exit?For????'j
????????????????????????End?If
????????????????????End?If
????????????????Next
????????????????If?Not?flag?Then????'沒有找到客戶端地址
????????????????????Debug.WriteLine("違法操作,該客戶端沒有申請(qǐng)過該工作站的數(shù)據(jù)!")
????????????????End?If
????????????????Exit?For????'i
????????????End?If
????????Next
????????If?Not?findsetup?Then
????????????Debug.WriteLine("沒有找到對(duì)應(yīng)的設(shè)備!非法操作!")
????????????Return?False
????????End?If
????????If?Not?flag?Then?????'沒有找到客戶端地址
????????????Debug.WriteLine("沒有找到對(duì)應(yīng)的客戶端地址!非法操作!")
????????????Return?False
????????End?If
????????'檢查當(dāng)前是否還有客戶端在接收數(shù)據(jù):
????????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?&?"?在接收數(shù)據(jù)!")
????????????????????flag?=?True?????????'找到一個(gè)!
????????????????End?If
????????????Next
????????Next
????????'Debug.WriteLine("用戶:"?&?ip.ToString?&?"需要取消接收數(shù)據(jù)")
????????'Debug.WriteLine(flag)
????????If?Not?flag?Then
????????????'當(dāng)前已經(jīng)沒有客戶端需要本工作站發(fā)送數(shù)據(jù)了,關(guān)閉開關(guān)
????????????on_off?=?False????????'關(guān)閉發(fā)送開關(guān)
????????????Debug.WriteLine("關(guān)閉發(fā)送開關(guān)!")
????????????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
????'用保持在線狀態(tài)的函數(shù)?
????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
????'用于向各個(gè)客戶端發(fā)送數(shù)據(jù),此函數(shù)通過Send線程控制:
????'這個(gè)函數(shù)只用來發(fā)送數(shù)據(jù)信息,即以40開頭的信息
????Public?Sub?DataMove()
????????Try
????????????Dim?data?As?String
????????????Dim?TempSend?As?String
????????????Dim?TempDev?As?ClassSetup
????????????Dim?i?As?Integer
????????????Debug.WriteLine("啟動(dòng)發(fā)送器:")
????????????While?on_off
????????????????Application.DoEvents()
????????????????If?SendDataList.Count?>?0?Then??????'如果發(fā)送的鏈表中有數(shù)據(jù),則按照順序發(fā)送:
????????????????????TempDev?=?CType(SendDataList.Item(0),?ClassData).myDevice???????'獲取是哪個(gè)設(shè)備要求發(fā)送的,空代表是本系統(tǒng)要求發(fā)送的,而不是某個(gè)設(shè)備的數(shù)據(jù)信息
????????????????????data?=?CType(SendDataList.Item(0),?ClassData).mydata????????????'獲取數(shù)據(jù)
????????????????????'發(fā)送本數(shù)據(jù):
????????????????????For?i?=?0?To?TempDev.SendTo.Length?-?1
????????????????????????If?Not?TempDev.SendTo(i)?Is?Nothing?Then????????????????????'向所有需要接收本設(shè)備的客戶端發(fā)送
????????????????????????????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("發(fā)送器結(jié)束")
????????Catch?ex?As?Exception
????????????Debug.WriteLine("DataMove:"?&?Err.Description)
????????End?Try
????End?Sub
????'將一整串長(zhǎng)數(shù)據(jù)發(fā)送到指定的ip地址:
????'格式:40+標(biāo)志量+數(shù)據(jù)
????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)??????????????????????????'獲取除了數(shù)據(jù)頭之外的所有數(shù)據(jù)
????????????If?thedata.Length?>?movelenth?Then??????????????????????????????????????????'第一次數(shù)據(jù)!
????????????????TempSend?=?head?&?"0"?&?thedata.Substring(0,?movelenth)?????????????????'添加0,表示數(shù)據(jù)的開始
????????????????thedata?=?thedata.Substring(movelenth,?thedata.Length?-?movelenth)??????'將發(fā)送出去的那些字符除掉
????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????ClientSocket.SendTo(sendbytes,?ip)??????????????????????????????????????'發(fā)送本段信息
????????????????Thread.Sleep(100)
????????????????While?thedata.Length?>?movelenth????????????????????????????????????????'如果剩下的數(shù)據(jù)大小大于可以發(fā)送的字節(jié)數(shù),則拆分
????????????????????'發(fā)送:
????????????????????TempSend?=?head?&?"2"?&?thedata.Substring(0,?movelenth)?????????????'添加2,表示數(shù)據(jù)的中間部分
????????????????????thedata?=?thedata.Substring(movelenth,?thedata.Length?-?movelenth)??'將發(fā)送出去的那些字符除掉
????????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????????ClientSocket.SendTo(sendbytes,?ip)??????????????????????????????????'發(fā)送本段信息
????????????????????Thread.Sleep(100)
????????????????End?While
????????????????If?thedata.Length?>?0?Then??????????????????????????????????????????????'發(fā)送最后一段信息
????????????????????TempSend?=?head?&?"1"?&?thedata?????????????????????????????????????'添加1,表示是數(shù)據(jù)的結(jié)束
????????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????????ClientSocket.SendTo(sendbytes,?ip)
????????????????????Thread.Sleep(100)
????????????????End?If
????????????Else
????????????????TempSend?=?head?&?"3"?&?thedata?????????????????????????????????????????'添加3,表示這里是全部數(shù)據(jù)一次性傳送完畢
????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????ClientSocket.SendTo(sendbytes,?ip)??????????????????????????????????????'發(fā)送本段信息
????????????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???????????'定義的循環(huán)變量j,得到本地機(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
????'發(fā)送本工作站的基本信息:(本函數(shù)執(zhí)行的時(shí)機(jī)由接口控制,一旦出現(xiàn)新的設(shè)備或配置完成即執(zhí)行一次)
????'如果需要發(fā)送的目標(biāo)為空,則說明是發(fā)送給服務(wù)器的
????'不為空,則是發(fā)送給某個(gè)客戶端的
????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,加上標(biāo)志位為512,乘以2為傳送的最大字節(jié)數(shù):1024
????????????'重新組合配置文件:
????????????If?sendtoEP?Is?Nothing?Then?sendtoEP?=?ServerEP
????????????While?tmpstr.Length?>?movelenth???????????????????????????????????'如果數(shù)據(jù)大小大于可以發(fā)送的字節(jié)數(shù),則拆分
????????????????'發(fā)送:
????????????????TempSend?=?head?&?"0"?&?tmpstr.Substring(0,?movelenth)????????'添加0,表示數(shù)據(jù)未結(jié)束
????????????????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?????????????????????????????????????????'發(fā)送最后一段信息
????????????????TempSend?=?head?&?"1"?&?tmpstr
????????????????sendBytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????ClientSocket.SendTo(sendBytes,?sendtoEP)
????????????????Thread.Sleep(100)
????????????End?If
????????????Debug.WriteLine("向"?&?sendtoEP.ToString?&?"發(fā)送配置信息")
????????????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
????'用于回應(yīng)服務(wù)器服務(wù)程序發(fā)送的探測(cè)信息
????'只是一個(gè)回應(yīng),不對(duì)服務(wù)器發(fā)回的確認(rèn)成功信息做任何處理
????Private?Sub?ReLogin(ByVal?TheServerEP?As?IPEndPoint)
????????Try
????????????Dim?userBytes?As?[Byte]()
????????????userBytes?=?Encoding.Unicode.GetBytes(LOGININ?&?username)
????????????'向服務(wù)器發(fā)送客戶消息?
????????????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兩個(gè)類參見上一篇文章:.net中的socket異步通信實(shí)現(xiàn)--服務(wù)器端代碼
那么在設(shè)計(jì)客戶端代碼時(shí)我們主要考慮哪些問題呢?
第一是如何接收數(shù)據(jù),往往一次傳輸?shù)臄?shù)據(jù)量較大,但socket一次的傳輸量是1024個(gè)byte,因此需要對(duì)數(shù)據(jù)在發(fā)送端進(jìn)行拆分,而在接收端進(jìn)行組合。
第二是需要建立緩沖區(qū),網(wǎng)絡(luò)傳輸?shù)乃俣瓤隙ū任覀兲幚頂?shù)據(jù)的速度快。
大家如果需要使用這段代碼,需要編寫一下其中的ClassSetup類,該類包含每個(gè)工作站的配置信息,由于版權(quán)問題,在這里就不公開了。
客戶端代碼如下:
Public?Class?ClassServer
#Region?"參數(shù)"
????'以下是客戶端到服務(wù)器端的消息開頭?
????Const?LOGININ?As?String?=?"10"?'請(qǐng)求登陸的消息|||消息形式:10+自己的用戶名?
????Const?LOGINOUT?As?String?=?"11"?'請(qǐng)求登出的消息|||消息形式:11+自己的用戶名?
????Const?GETULIST?As?String?=?"12"?'請(qǐng)求獲得在線用戶列表|||消息形式:12+自己的用戶名?
????Const?P2PCONN?As?String?=?"13"?'請(qǐng)求P2P連接的消息|||消息形式:13+自己的用戶名+對(duì)方的用戶名?
????Const?HOLDLINE?As?String?=?"14"?'保持連接.|||消息開式:14+自己的用戶名?
????'以下是服務(wù)器到客戶端的消息開頭?
????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"?'服務(wù)器關(guān)閉?
????Const?MSGEND?As?String?=?"25"?'消息結(jié)束?
????Const?ONEOFF?As?String?=?"26"?'一個(gè)客戶端下線(超時(shí)下線)
????Const?SEARCHCLIENT?As?String?=?"27"?'探測(cè)各個(gè)客戶端是否存在
????'以下是客戶端到客戶端的消息開頭?
????Const?HOLDOK?As?String?=?"30"?'打洞成功?
????Const?CHATMSG?As?String?=?"31"?'聊天消息?
????Const?CHTMSGEND?As?String?=?"32"?'聊天消息發(fā)送成功?
????Const?GIVEMEDATA?As?String?=?"33"?'添加數(shù)據(jù)訂閱
????Const?NODATASEND?As?String?=?"34"?'取消數(shù)據(jù)訂閱
????Const?GETDEVINFO?As?String?=?"35"?'獲取工作站的基本信息
????'以下是工作站發(fā)送到客戶端的命令:
????Const?RECDEVINFO?As?String?=?"45"?'工作站發(fā)送給服務(wù)器的設(shè)備配置信息
????Const?DATA?As?String?=?"40"???????'表示發(fā)送的是數(shù)據(jù)信息,由工作站發(fā)送給客戶端
????'以下是客戶端的命名?
????Const?EXITPRO?As?String?=?"EXIT"?'退出命令?
????Const?SHOWULIST?As?String?=?"SHOWUSER"?'顯示在線用戶?
????Const?HELP?As?String?=?"HELP"?'顯示幫助?
????Const?SEND?As?String?=?"SEND"?'發(fā)送消息?
????'Const?OldData?As?String?=?"40"
#End?Region
#Region?"全局變量"
????Delegate?Sub?myMethodDelegate(ByRef?myInData?As?Byte())?'登陸時(shí)用的事件?
????Dim?msgSendEnd?As?Boolean?=?False?'消息是否發(fā)送成功,若發(fā)送成功,則會(huì)返回結(jié)束消息?
????Dim?ThListen?As?New?Thread(AddressOf?listen)?'監(jiān)聽的線程?
????Dim?ThSend?As?Thread?=?Nothing
????Dim?ClientSocket?As?New?Socket(AddressFamily.InterNetwork,?SocketType.Dgram,?ProtocolType.Udp)?'客戶端套節(jié)字的定義?
????Public?username?As?String?'當(dāng)前用戶名?
????Dim?ServerEP?As?IPEndPoint?'服務(wù)器的IPEP?
????Dim?holdBytes?As?[Byte]()?=?Encoding.Unicode.GetBytes(HOLDLINE?&?username)?'和服務(wù)器保持連接連接時(shí)用到的byte數(shù)組?
????Dim?getUrecCount?As?Integer
????Dim?testHold?As?Boolean?=?False
????Dim?testChat?As?Boolean?=?False
????Private?receiveDone?As?ManualResetEvent?'在登陸時(shí)用來阻塞線程,等待收到數(shù)據(jù)?
????Private?sendDone?As?ManualResetEvent?'用來陰塞發(fā)送消息的線程.等待收到回送的確認(rèn)消息??
????Private?holdDone?As?ManualResetEvent?'用來阻塞打洞時(shí)的線程?
????Private?chatDone?As?ManualResetEvent?'用來阻塞發(fā)送聊天消息時(shí)的線程?
????Public?Connected?As?Boolean?=?True???'用來表示是否和服務(wù)器連接成功
????Dim?timerDelegate?As?New?TimerCallback(AddressOf?holdonline)?'為保持在線狀態(tài)弄得?
????Private?mytimer?As?Timer
????Public?on_off?As?Boolean?=?False????'表示發(fā)送開關(guān)是否打開,有主任端連接即打開此開關(guān),所有連接的主任端下線后即關(guān)閉
????Public?SendDataList?As?ArrayList
????Const?movelenth?As?Integer?=?509?'最大為511,加上標(biāo)志位為512,乘以2為傳送的最大字節(jié)數(shù):1024
????Private?sw?As?StreamWriter
????Private?dealing?As?Boolean?=?False
????Private?ReceiveDataList?As?DataQueue
????'此數(shù)為減去頭一個(gè)標(biāo)志位(表示此段是否結(jié)束:0表示未結(jié)束;1表示結(jié)束)剩余的字符長(zhǎng)度
#End?Region
#Region?"方法"
????Public?Event?SendDDIinfo(ByVal?TgIP?As?IPEndPoint)
????Public?Event?NetWorkError(ByVal?ErrStr?As?String)
????'主函數(shù),程序入口,放到splash中運(yùn)行:?
????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)??'正式版本專用,從注冊(cè)表讀取服務(wù)器地址
????????????End?If
????????????sw?=?New?StreamWriter(Directory.GetCurrentDirectory?&?"\DataServer.log",?True)
????????????AddHandler?SendDDIinfo,?AddressOf?SendBasicInfo
????????????'********測(cè)試專用,測(cè)試版本不讀注冊(cè)表,本機(jī)就是服務(wù)器!********
????????????'If?getIdOfLocalhost()?=?""?Then
????????????'????'獲取不到本機(jī)地址則退出
????????????'????RaiseEvent?NetWorkError("找不到存在的連接")
????????????'????Exit?Sub
????????????'End?If
????????????'假設(shè)本機(jī)只有一塊網(wǎng)卡,邦定一個(gè)ip地址和端口(5555)
????????????'正式版從注冊(cè)表中讀取GUID作為名稱:
????????????'模擬版本獲取主機(jī)名為登錄名稱:
????????????username?=?"DataServer?"?&?Dns.GetHostName
????????????Dim?LocalEP?As?New?IPEndPoint(IPAddress.Any,?5555)
????????????ClientSocket.Bind(LocalEP)??????'綁定本機(jī)端口
????????????ReceiveDataList?=?New?DataQueue
????????????'根據(jù)注冊(cè)表中的ServerIp,向指定的服務(wù)器端口(11000)登錄:
????????????Dim?i?As?Int16?=?1
????????????While?Not?Login()
????????????????If?i?>?2?Then??????'三次登錄失敗,則退出循環(huán),直接幫定本機(jī)ip的5555端口。保證可以正常通訊
????????????????????Me.Connected?=?False
????????????????????RaiseEvent?NetWorkError("登錄失敗!")
????????????????????Exit?While
????????????????End?If
????????????????i?+=?1
????????????End?While
????????????'登陸成功后.用一個(gè)timer,每隔50秒向服務(wù)器發(fā)送消息,保持在線狀態(tài)跟在主機(jī)注冊(cè)的端口?
????????????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
????'退出服務(wù)器的管理
????Public?Sub?ExitProcess()
????????Try?'
????????????sw.Close()
????????????sw?=?Nothing
????????????exitApp()
????????????ClientSocket.Close()
????????????mytimer.Dispose()
????????????ThListen.Abort()
????????????Debug.WriteLine("成功下線!")
????????Catch?ex?As?Exception
????????????Debug.WriteLine("ExitProcess中報(bào)錯(cuò):"?&?ex.Message)
????????End?Try
????End?Sub
????'一個(gè)工作站登陸到服務(wù)器
????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)
????????????'向服務(wù)器發(fā)送客戶消息?
????????????ClientSocket.SendTo(userBytes,?ServerEP)
????????????Dim?data?As?[Byte]()?=?New?Byte(1024)?{}
????????????Dim?comStr?As?String?=?Encoding.Unicode.GetString(data,?0,?4)
????????????'異面的接收服務(wù)器回送的消息?
????????????Dim?DGrecv?As?New?myMethodDelegate(AddressOf?recvLogin)
????????????DGrecv.BeginInvoke(data,?Nothing,?Nothing)
????????????'等待服務(wù)器回送消息的時(shí)長(zhǎng)為10秒,否則為服務(wù)器超時(shí)?
????????????receiveDone.WaitOne(500,?True)
????????????Dim?recvStr?As?String?=?Encoding.Unicode.GetString(data,?0,?4)
????????????If?recvStr?=?comStr?Then
????????????????Debug.WriteLine("服務(wù)器超時(shí).登陸失敗!!")
????????????????Return?False
????????????End?If
????????????If?Encoding.Unicode.GetString(data,?0,?4)?=?LOGINOK?Then
????????????????Debug.WriteLine("登陸成功!!")
????????????????Return?True
????????????Else
????????????????Debug.WriteLine("服務(wù)器未知錯(cuò)誤,登陸失敗!!")
????????????????Return?False
????????????End?If
????????Catch?ex?As?Exception
????????????Debug.WriteLine("Login:"?&?Err.Description)
????????End?Try
????End?Function
????'解除登陸函數(shù)中的線程阻止
????Sub?recvLogin(ByRef?inData?As?Byte())
????????ClientSocket.Receive(inData)
????????receiveDone.Set()
????End?Sub
????'登出函數(shù)?
????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
????'客戶程序監(jiān)聽的函數(shù)?
????Sub?listen()
????????While?True
????????????Try
????????????????Dim?recv?As?Integer?=?0?'收到的字節(jié)數(shù)?
????????????????Dim?datas?As?[Byte]()?=?New?Byte(1024)?{}?'緩沖區(qū)大小?
????????????????Dim?sender?As?New?IPEndPoint(IPAddress.Any,?0)
????????????????Dim?tempRemoteEP?As?EndPoint?=?CType(sender,?EndPoint)
????????????????recv?=?ClientSocket.ReceiveFrom(datas,?tempRemoteEP)??????'data存放接收到的數(shù)據(jù),tempRemoteEP存放發(fā)送來的ip地址
????????????????Dim?tmpdata?As?New?DeclearData(datas,?tempRemoteEP,?recv)????'裝進(jìn)信息塊中
????????????????ReceiveDataList.AddItem(tmpdata)????????????????????????????'將信息塊裝進(jìn)本程序自己的緩沖區(qū)
????????????????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
????'處理不同機(jī)器發(fā)送過來的信息
????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
????????????????????????????????'如果有一個(gè)節(jié)點(diǎn)登陸:
????????????????????????????????'暫時(shí)不做處理
????????????????????????????Case?GIVEMEDATA?????????'添加一個(gè)接收數(shù)據(jù)的監(jiān)視端
????????????????????????????????If?Not?on_off?Then
????????????????????????????????????on_off?=?True???????'打開開關(guān)
????????????????????????????????????If?ThSend?Is?Nothing?Then???'如果此時(shí)發(fā)送數(shù)據(jù)的線程沒有啟動(dòng),則啟動(dòng)它
????????????????????????????????????????ThSend?=?New?Thread(AddressOf?DataMove)
????????????????????????????????????????ThSend.Start()
????????????????????????????????????????Debug.WriteLine("開始發(fā)送數(shù)據(jù)!")
????????????????????????????????????End?If
????????????????????????????????End?If
????????????????????????????????AddRss(tmpmsg.datastr,?tmpmsg.fromip)
????????????????????????????Case?NODATASEND?????????'取消一個(gè)接收數(shù)據(jù)的監(jiān)視端
????????????????????????????????RemoveRss(tmpmsg.datastr,?tmpmsg.fromip)
????????????????????????????Case?MSGEND?????????????'控制數(shù)據(jù)發(fā)送成功返回標(biāo)志
????????????????????????????????msgSendEnd?=?True
????????????????????????????????sendDone.Set()
????????????????????????????Case?HOLDOK?????????????'保持在線信息返回
????????????????????????????????testHold?=?True
????????????????????????????????holdDone.Set()
????????????????????????????Case?CHTMSGEND??????????'發(fā)送聊天信息返回標(biāo)志
????????????????????????????????testChat?=?True
????????????????????????????????chatDone.Set()
????????????????????????????Case?GETDEVINFO
????????????????????????????????'要求發(fā)送本工作站的基本信息:
????????????????????????????????SendBasicInfo(tmpmsg.fromip)
????????????????????????????Case?ONEOFF
????????????????????????????????'某個(gè)客戶端超時(shí)下線:
????????????????????????????????'檢驗(yàn)此信息是否為服務(wù)器正確端口發(fā)送
????????????????????????????????'檢測(cè)該客戶端是否正在接收我們的數(shù)據(jù),如果是則終止
????????????????????????????Case?SEARCHCLIENT
????????????????????????????????ReLogin(tmpmsg.fromip)
????????????????????????????Case?Else
????????????????????????End?Select
????????????????????End?If
????????????????Catch?ex?As?Exception
????????????????????Debug.WriteLine("錯(cuò)誤的數(shù)據(jù):"?&?tmpmsg.datastr)
????????????????????Debug.WriteLine("DealData:"?&?Err.Description)
????????????????????WriteLog("錯(cuò)誤的數(shù)據(jù):"?&?tmpmsg.datastr)
????????????????????WriteLog("DealData:"?&?Err.Description)
????????????????Finally
????????????????????ReceiveDataList.Remove()
????????????????End?Try
????????????End?While
????????????dealing?=?False
????????End?If
????End?Sub
????'一個(gè)客戶端發(fā)送請(qǐng)求,要求本工作站向其發(fā)送數(shù)據(jù),此請(qǐng)求只能由客戶端發(fā)送
????'向設(shè)備實(shí)例的SendTO()數(shù)組添加該工作站的IP地址(本程序只向固定端口發(fā)送數(shù)據(jù)!)
????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
????????????????????????????'這個(gè)設(shè)備本來就向該客戶端發(fā)送數(shù)據(jù)
????????????????????????????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??????????'正是要申請(qǐng)的設(shè)備,進(jìn)行下一步判斷:
????????????????????findsetup?=?True????'找到了這個(gè)設(shè)備
????????????????????If?tmpsetup.SendTo?Is?Nothing?Then
????????????????????????ReDim?Preserve?tmpsetup.SendTo(1)
????????????????????????tmpsetup.SendTo(0)?=?New?IPEndPoint(ip.Address,?5556)???????????'第一個(gè)申請(qǐng)的客戶端
????????????????????????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???'重復(fù)申請(qǐng)
????????????????????????????????Debug.WriteLine("該客戶端已經(jīng)在接收數(shù)據(jù)了!這是違法操作!")
????????????????????????????????flag?=?True
????????????????????????????????Exit?For????'j
????????????????????????????End?If
????????????????????????Next?j
????????????????????????If?Not?flag?Then????????'正常的申請(qǐng)數(shù)據(jù)
????????????????????????????flag?=?False????????'檢查前面是否有空的數(shù)組元素可用
????????????????????????????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????'沒有找到可用的,重新擴(kuò)展數(shù)組
????????????????????????????????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("沒有找到該設(shè)備,ID信息錯(cuò)誤!")
????????????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
????'取消從本工作站獲取數(shù)據(jù)
????'這個(gè)消息只由客戶端發(fā)送
????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
????????????????'該客戶端下線,取消所有向此客戶端的發(fā)送:
????????????????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??????'找到該設(shè)備
????????????????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???????'找到了這個(gè)客戶端地址
????????????????????????????tmpsetup.SendTo(j)?=?Nothing
????????????????????????????flag?=?True
????????????????????????????'Exit?For????'j
????????????????????????End?If
????????????????????End?If
????????????????Next
????????????????If?Not?flag?Then????'沒有找到客戶端地址
????????????????????Debug.WriteLine("違法操作,該客戶端沒有申請(qǐng)過該工作站的數(shù)據(jù)!")
????????????????End?If
????????????????Exit?For????'i
????????????End?If
????????Next
????????If?Not?findsetup?Then
????????????Debug.WriteLine("沒有找到對(duì)應(yīng)的設(shè)備!非法操作!")
????????????Return?False
????????End?If
????????If?Not?flag?Then?????'沒有找到客戶端地址
????????????Debug.WriteLine("沒有找到對(duì)應(yīng)的客戶端地址!非法操作!")
????????????Return?False
????????End?If
????????'檢查當(dāng)前是否還有客戶端在接收數(shù)據(jù):
????????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?&?"?在接收數(shù)據(jù)!")
????????????????????flag?=?True?????????'找到一個(gè)!
????????????????End?If
????????????Next
????????Next
????????'Debug.WriteLine("用戶:"?&?ip.ToString?&?"需要取消接收數(shù)據(jù)")
????????'Debug.WriteLine(flag)
????????If?Not?flag?Then
????????????'當(dāng)前已經(jīng)沒有客戶端需要本工作站發(fā)送數(shù)據(jù)了,關(guān)閉開關(guān)
????????????on_off?=?False????????'關(guān)閉發(fā)送開關(guān)
????????????Debug.WriteLine("關(guān)閉發(fā)送開關(guān)!")
????????????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
????'用保持在線狀態(tài)的函數(shù)?
????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
????'用于向各個(gè)客戶端發(fā)送數(shù)據(jù),此函數(shù)通過Send線程控制:
????'這個(gè)函數(shù)只用來發(fā)送數(shù)據(jù)信息,即以40開頭的信息
????Public?Sub?DataMove()
????????Try
????????????Dim?data?As?String
????????????Dim?TempSend?As?String
????????????Dim?TempDev?As?ClassSetup
????????????Dim?i?As?Integer
????????????Debug.WriteLine("啟動(dòng)發(fā)送器:")
????????????While?on_off
????????????????Application.DoEvents()
????????????????If?SendDataList.Count?>?0?Then??????'如果發(fā)送的鏈表中有數(shù)據(jù),則按照順序發(fā)送:
????????????????????TempDev?=?CType(SendDataList.Item(0),?ClassData).myDevice???????'獲取是哪個(gè)設(shè)備要求發(fā)送的,空代表是本系統(tǒng)要求發(fā)送的,而不是某個(gè)設(shè)備的數(shù)據(jù)信息
????????????????????data?=?CType(SendDataList.Item(0),?ClassData).mydata????????????'獲取數(shù)據(jù)
????????????????????'發(fā)送本數(shù)據(jù):
????????????????????For?i?=?0?To?TempDev.SendTo.Length?-?1
????????????????????????If?Not?TempDev.SendTo(i)?Is?Nothing?Then????????????????????'向所有需要接收本設(shè)備的客戶端發(fā)送
????????????????????????????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("發(fā)送器結(jié)束")
????????Catch?ex?As?Exception
????????????Debug.WriteLine("DataMove:"?&?Err.Description)
????????End?Try
????End?Sub
????'將一整串長(zhǎng)數(shù)據(jù)發(fā)送到指定的ip地址:
????'格式:40+標(biāo)志量+數(shù)據(jù)
????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)??????????????????????????'獲取除了數(shù)據(jù)頭之外的所有數(shù)據(jù)
????????????If?thedata.Length?>?movelenth?Then??????????????????????????????????????????'第一次數(shù)據(jù)!
????????????????TempSend?=?head?&?"0"?&?thedata.Substring(0,?movelenth)?????????????????'添加0,表示數(shù)據(jù)的開始
????????????????thedata?=?thedata.Substring(movelenth,?thedata.Length?-?movelenth)??????'將發(fā)送出去的那些字符除掉
????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????ClientSocket.SendTo(sendbytes,?ip)??????????????????????????????????????'發(fā)送本段信息
????????????????Thread.Sleep(100)
????????????????While?thedata.Length?>?movelenth????????????????????????????????????????'如果剩下的數(shù)據(jù)大小大于可以發(fā)送的字節(jié)數(shù),則拆分
????????????????????'發(fā)送:
????????????????????TempSend?=?head?&?"2"?&?thedata.Substring(0,?movelenth)?????????????'添加2,表示數(shù)據(jù)的中間部分
????????????????????thedata?=?thedata.Substring(movelenth,?thedata.Length?-?movelenth)??'將發(fā)送出去的那些字符除掉
????????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????????ClientSocket.SendTo(sendbytes,?ip)??????????????????????????????????'發(fā)送本段信息
????????????????????Thread.Sleep(100)
????????????????End?While
????????????????If?thedata.Length?>?0?Then??????????????????????????????????????????????'發(fā)送最后一段信息
????????????????????TempSend?=?head?&?"1"?&?thedata?????????????????????????????????????'添加1,表示是數(shù)據(jù)的結(jié)束
????????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????????ClientSocket.SendTo(sendbytes,?ip)
????????????????????Thread.Sleep(100)
????????????????End?If
????????????Else
????????????????TempSend?=?head?&?"3"?&?thedata?????????????????????????????????????????'添加3,表示這里是全部數(shù)據(jù)一次性傳送完畢
????????????????sendbytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????ClientSocket.SendTo(sendbytes,?ip)??????????????????????????????????????'發(fā)送本段信息
????????????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???????????'定義的循環(huán)變量j,得到本地機(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
????'發(fā)送本工作站的基本信息:(本函數(shù)執(zhí)行的時(shí)機(jī)由接口控制,一旦出現(xiàn)新的設(shè)備或配置完成即執(zhí)行一次)
????'如果需要發(fā)送的目標(biāo)為空,則說明是發(fā)送給服務(wù)器的
????'不為空,則是發(fā)送給某個(gè)客戶端的
????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,加上標(biāo)志位為512,乘以2為傳送的最大字節(jié)數(shù):1024
????????????'重新組合配置文件:
????????????If?sendtoEP?Is?Nothing?Then?sendtoEP?=?ServerEP
????????????While?tmpstr.Length?>?movelenth???????????????????????????????????'如果數(shù)據(jù)大小大于可以發(fā)送的字節(jié)數(shù),則拆分
????????????????'發(fā)送:
????????????????TempSend?=?head?&?"0"?&?tmpstr.Substring(0,?movelenth)????????'添加0,表示數(shù)據(jù)未結(jié)束
????????????????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?????????????????????????????????????????'發(fā)送最后一段信息
????????????????TempSend?=?head?&?"1"?&?tmpstr
????????????????sendBytes?=?Encoding.Unicode.GetBytes(TempSend)
????????????????ClientSocket.SendTo(sendBytes,?sendtoEP)
????????????????Thread.Sleep(100)
????????????End?If
????????????Debug.WriteLine("向"?&?sendtoEP.ToString?&?"發(fā)送配置信息")
????????????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
????'用于回應(yīng)服務(wù)器服務(wù)程序發(fā)送的探測(cè)信息
????'只是一個(gè)回應(yīng),不對(duì)服務(wù)器發(fā)回的確認(rèn)成功信息做任何處理
????Private?Sub?ReLogin(ByVal?TheServerEP?As?IPEndPoint)
????????Try
????????????Dim?userBytes?As?[Byte]()
????????????userBytes?=?Encoding.Unicode.GetBytes(LOGININ?&?username)
????????????'向服務(wù)器發(fā)送客戶消息?
????????????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兩個(gè)類參見上一篇文章:.net中的socket異步通信實(shí)現(xiàn)--服務(wù)器端代碼
轉(zhuǎn)載于:https://www.cnblogs.com/yyshenren/archive/2008/07/10/1240154.html
總結(jié)
以上是生活随笔為你收集整理的.net中的socket异步通信实现--客户端代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP之Smarty简单实现
- 下一篇: 性能测试中批量数据制作实例的多种方法讨论