tcpCommClient.vb 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. Imports System.Threading
  2. Imports System.Net
  3. Imports System.Net.Sockets
  4. Imports System.IO
  5. Public Class tcpCommClient
  6. Public errMsg As String
  7. ' Define the delegate type
  8. Public Delegate Sub ClientCallbackDelegate(ByVal bytes() As Byte, ByVal dataChannel As Integer)
  9. ' Create Delegate pointer
  10. Public ClientCallbackObject As ClientCallbackDelegate
  11. ' Monitor CPU usage
  12. 'Private CPUutil As CpuMonitor
  13. Private continue_running As Boolean = False
  14. Private bytes() As Byte
  15. Private blockSize As UInt16
  16. Private IP As System.Net.IPAddress
  17. Private Port As Integer
  18. Private localAddr As IPAddress
  19. Private Client As TcpClient
  20. Private Stream As NetworkStream
  21. Private fileWriter As clsAsyncUnbuffWriter
  22. Private fileReader As FileStream
  23. Private FileBeingSentPath As String
  24. Private weHaveThePuck As Boolean = False
  25. Private isRunning As Boolean = False
  26. Private UserBytesToBeSentAvailable As Boolean = False
  27. Private UserBytesToBeSent As New MemoryStream
  28. Private UserOutputChannel As Byte
  29. Private SystemBytesToBeSentAvailable As Boolean = False
  30. Private SystemBytesToBeSent() As Byte
  31. Private SystemOutputChannel As Byte
  32. Private SendingFile As Boolean = False
  33. Private ReceivingFile As Boolean = False
  34. Private IncomingFileName As String
  35. Private IncomingFileSize As Int64 = 0
  36. Private outgoingFileSize As UInt64 = 0
  37. Private outgoingFileName As String
  38. Private fileBytesRecieved As Int64 = 0
  39. Private filebytesSent As Int64 = 0
  40. Private bytesSentThisSecond As Int32 = 0
  41. Private bytesReceivedThisSecond As Int32 = 0
  42. Private mbpsOneSecondAverage() As Int32
  43. Private ReceivedFilesFolder As String = Application.StartupPath & "\ReceivedFiles"
  44. Private userName As String
  45. Private password As String
  46. Private mbpsSyncObject As New AutoResetEvent(False)
  47. Private Function StrToByteArray(ByVal text As String) As Byte()
  48. Dim encoding As New System.Text.UTF8Encoding()
  49. StrToByteArray = encoding.GetBytes(text)
  50. End Function
  51. Private Function BytesToString(ByVal data() As Byte) As String
  52. Dim enc As New System.Text.UTF8Encoding()
  53. BytesToString = enc.GetString(data)
  54. End Function
  55. Public Function isClientRunning() As Boolean
  56. Return isRunning
  57. End Function
  58. Public Function SetReceivedFilesFolder(ByVal _path As String) As Boolean
  59. ReceivedFilesFolder = _path
  60. End Function
  61. Public Function GetIncomingFileName() As String
  62. Return IncomingFileName
  63. End Function
  64. Public Function GetOutgoingFileName() As String
  65. Return outgoingFileName
  66. End Function
  67. Public Function GetPercentOfFileReceived() As UInt16
  68. If ReceivingFile Then
  69. Return CUShort((fileBytesRecieved / IncomingFileSize) * 100)
  70. Else
  71. Return 0
  72. End If
  73. End Function
  74. Public Function GetPercentOfFileSent() As UInt16
  75. If SendingFile Then
  76. Return CUShort((filebytesSent / outgoingFileSize) * 100)
  77. Else
  78. Return 0
  79. End If
  80. End Function
  81. Public Function GetMbps() As String
  82. Dim currentMbps As Decimal = CalculateMbps(True)
  83. If currentMbps > 1000000 Then
  84. Return (currentMbps / 1000000).ToString("N2") & " Mbps"
  85. Else
  86. Return (currentMbps / 1000).ToString("N2") & " Kbps"
  87. End If
  88. End Function
  89. Public Function GetLocalIpAddress() As System.Net.IPAddress
  90. Dim strHostName As String
  91. Dim addresses() As System.Net.IPAddress
  92. strHostName = System.Net.Dns.GetHostName()
  93. addresses = System.Net.Dns.GetHostAddresses(strHostName)
  94. ' Find an IpV4 address
  95. For Each address As System.Net.IPAddress In addresses
  96. If address.ToString.Contains(".") then
  97. Return address
  98. End If
  99. Next
  100. ' No IpV4 address? Return the loopback address.
  101. Return System.Net.IPAddress.Loopback
  102. End Function
  103. Public Sub New(ByRef callbackMethod As ClientCallbackDelegate)
  104. blockSize = 10000
  105. ' Initialize the delegate variable to point to the user's callback method.
  106. ClientCallbackObject = callbackMethod
  107. End Sub
  108. Public Sub Connect(ByVal IP_Address As String, ByVal prt As Integer)
  109. Port = prt
  110. IP = System.Net.IPAddress.Parse(IP_Address)
  111. continue_running = True
  112. Dim clientCommunicationThread As New Thread(AddressOf Run)
  113. clientCommunicationThread.Name = "ClientCommunication"
  114. clientCommunicationThread.Start()
  115. End Sub
  116. Public Sub StopRunning()
  117. continue_running = False
  118. End Sub
  119. Public Function GetBlocksize() As UInt16
  120. Return blockSize
  121. End Function
  122. Public Function GetFile(ByVal _path As String) As Boolean
  123. Do
  124. If Not UserBytesToBeSentAvailable Then
  125. SyncLock UserBytesToBeSent
  126. UserBytesToBeSent.Close()
  127. UserBytesToBeSent = Nothing
  128. UserBytesToBeSent = New MemoryStream(StrToByteArray("GFR:" & _path))
  129. UserOutputChannel = 254 ' Text messages / commands on channel 254
  130. UserBytesToBeSentAvailable = True
  131. End SyncLock
  132. Exit Do
  133. End If
  134. If theClientIsStopping() Then Exit Function
  135. Application.DoEvents()
  136. Loop
  137. End Function
  138. Public Function SendFile(ByVal _path As String) As Boolean
  139. Do
  140. If Not UserBytesToBeSentAvailable Then
  141. SyncLock UserBytesToBeSent
  142. UserBytesToBeSent.Close()
  143. UserBytesToBeSent = Nothing
  144. UserBytesToBeSent = New MemoryStream(StrToByteArray("SFR:" & _path))
  145. UserOutputChannel = 254 ' Text messages / commands on channel 254
  146. UserBytesToBeSentAvailable = True
  147. End SyncLock
  148. Exit Do
  149. End If
  150. If theClientIsStopping() Then Exit Function
  151. Application.DoEvents()
  152. Loop
  153. End Function
  154. Public Sub CancelIncomingFileTransfer()
  155. Do
  156. If Not UserBytesToBeSentAvailable Then
  157. SyncLock UserBytesToBeSent
  158. UserBytesToBeSent.Close()
  159. UserBytesToBeSent = Nothing
  160. UserBytesToBeSent = New MemoryStream(StrToByteArray("Abort->"))
  161. UserOutputChannel = 254
  162. UserBytesToBeSentAvailable = True
  163. End SyncLock
  164. Exit Do
  165. End If
  166. If theClientIsStopping() Then Exit Sub
  167. Application.DoEvents()
  168. Loop
  169. FinishReceivingTheFile()
  170. Try
  171. File.Delete(ReceivedFilesFolder & "\" & IncomingFileName)
  172. Catch ex As Exception
  173. End Try
  174. End Sub
  175. Public Sub CancelOutgoingFileTransfer()
  176. Do
  177. If Not UserBytesToBeSentAvailable Then
  178. SyncLock UserBytesToBeSent
  179. UserBytesToBeSent.Close()
  180. UserBytesToBeSent = Nothing
  181. UserBytesToBeSent = New MemoryStream(StrToByteArray("Abort<-"))
  182. UserOutputChannel = 254
  183. UserBytesToBeSentAvailable = True
  184. End SyncLock
  185. Exit Do
  186. End If
  187. If theClientIsStopping() Then Exit Sub
  188. Application.DoEvents()
  189. Loop
  190. StopSendingTheFile()
  191. End Sub
  192. Public Function SendBytes(ByVal bytes() As Byte, Optional ByVal channel As Byte = 1) As Boolean
  193. If channel = 0 Or channel > 250 Then
  194. MsgBox("Data can not be sent using channel numbers less then 1 or greater then 250.", MsgBoxStyle.Critical, "TCP_Client")
  195. Exit Function
  196. End If
  197. Do
  198. If Not UserBytesToBeSentAvailable Then
  199. SyncLock UserBytesToBeSent
  200. UserBytesToBeSent.Close()
  201. UserBytesToBeSent = Nothing
  202. UserBytesToBeSent = New MemoryStream(bytes)
  203. UserOutputChannel = channel
  204. UserBytesToBeSentAvailable = True
  205. End SyncLock
  206. Exit Do
  207. End If
  208. If theClientIsStopping() Then Exit Function
  209. Application.DoEvents()
  210. Loop
  211. End Function
  212. Private Function RcvBytes(ByVal data() As Byte, Optional ByVal dataChannel As Integer = 1) As Boolean
  213. ' dataType: >0 = data channel, 251 and up = internal messages. 0 is an invalid channel number (it's the puck)
  214. If dataChannel < 1 Then
  215. RcvBytes = False
  216. Exit Function
  217. End If
  218. Try
  219. ClientCallbackObject(data, dataChannel)
  220. Catch ex As Exception
  221. RcvBytes = False
  222. ' An unexpected error.
  223. Debug.WriteLine("Unexpected error in Client\RcvBytes: " & ex.Message)
  224. End Try
  225. End Function
  226. Private Function CreateFolders(ByVal _path As String) As Boolean
  227. CreateFolders = True
  228. Dim parts() As String
  229. Dim path As String = ""
  230. Dim count As Int32
  231. parts = Split(_path, "\")
  232. path = parts(0)
  233. For count = 1 To parts.Length - 2
  234. path += "\" & parts(count)
  235. Try
  236. If Not Directory.Exists(path) Then
  237. Directory.CreateDirectory(path)
  238. End If
  239. Catch ex As Exception
  240. End Try
  241. Next
  242. End Function
  243. Private Function SendExternalSystemMessage(ByVal message As String) As Boolean
  244. SystemBytesToBeSent = StrToByteArray(message)
  245. SystemOutputChannel = 254 ' Text messages / commands on channel 254
  246. SystemBytesToBeSentAvailable = True
  247. End Function
  248. Private Function BeginToReceiveAFile(ByVal _path As String) As Boolean
  249. Dim readBuffer As Int32 = 0
  250. ReceivingFile = True
  251. BeginToReceiveAFile = True
  252. fileBytesRecieved = 0
  253. Try
  254. CreateFolders(_path)
  255. fileWriter = New clsAsyncUnbuffWriter(_path, True, _
  256. 1024 * (clsAsyncUnbuffWriter.GetPageSize()), IncomingFileSize)
  257. Catch ex As Exception
  258. _path = ex.Message
  259. ReceivingFile = False
  260. End Try
  261. If Not ReceivingFile Then
  262. Try
  263. fileWriter.Close()
  264. Catch ex As Exception
  265. End Try
  266. Return False
  267. End If
  268. End Function
  269. Private Function HandleIncomingFileBytes(ByRef bytes() As Byte) As Boolean
  270. Try
  271. fileWriter.Write(bytes, bytes.Length)
  272. HandleIncomingFileBytes = True
  273. Catch ex As Exception
  274. HandleIncomingFileBytes = False
  275. End Try
  276. End Function
  277. Private Sub FinishReceivingTheFile()
  278. Try
  279. fileWriter.Close()
  280. fileWriter = Nothing
  281. ReceivingFile = False
  282. Catch ex As Exception
  283. ReceivingFile = False
  284. End Try
  285. End Sub
  286. Private Sub StopSendingTheFile()
  287. Try
  288. SendingFile = False
  289. fileReader.Close()
  290. fileReader = Nothing
  291. GC.GetTotalMemory(True)
  292. Catch ex As Exception
  293. SendingFile = False
  294. GC.GetTotalMemory(True)
  295. End Try
  296. End Sub
  297. Private Sub WrapUpIncomingFile()
  298. If ReceivingFile Then
  299. Try
  300. fileWriter.Close()
  301. fileWriter = Nothing
  302. GC.GetTotalMemory(True)
  303. Catch ex As Exception
  304. End Try
  305. Try
  306. File.Delete(ReceivedFilesFolder & "\" & IncomingFileName)
  307. Catch ex As Exception
  308. End Try
  309. End If
  310. End Sub
  311. Private Function CheckSessionPermissions(ByVal cmd As String) As Boolean
  312. ' Your security code here...
  313. Return True
  314. End Function
  315. Private Function BeginFileSend(ByVal _path As String, ByVal fileLength As Long) As Boolean
  316. filebytesSent = 0
  317. Try
  318. fileReader = New FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.None, clsAsyncUnbuffWriter.GetPageSize)
  319. SendingFile = True
  320. BeginFileSend = True
  321. Catch ex As Exception
  322. BeginFileSend = False
  323. _path = ex.Message
  324. SendingFile = False
  325. End Try
  326. Try
  327. If Not BeginFileSend Then fileReader.Close()
  328. Catch ex As Exception
  329. End Try
  330. End Function
  331. Private Sub GetMoreFileBytesIfAvailable()
  332. Dim bytesRead As Integer
  333. If SendingFile And Not SystemBytesToBeSentAvailable Then
  334. Try
  335. If SystemBytesToBeSent.Length <> blockSize Then ReDim SystemBytesToBeSent(blockSize - 1)
  336. bytesRead = fileReader.Read(SystemBytesToBeSent, 0, blockSize)
  337. If bytesRead <> blockSize Then ReDim Preserve SystemBytesToBeSent(bytesRead - 1)
  338. If bytesRead > 0 Then
  339. SystemOutputChannel = 252 ' File transfer from client to server
  340. SystemBytesToBeSentAvailable = True
  341. filebytesSent += bytesRead
  342. Else
  343. ReDim SystemBytesToBeSent(blockSize - 1)
  344. SendExternalSystemMessage("<-Done") ' Send the server a completion notice.
  345. SystemMessage("<-Done")
  346. SendingFile = False
  347. ' Clean up
  348. fileReader.Close()
  349. fileReader = Nothing
  350. GC.GetTotalMemory(True)
  351. End If
  352. Catch ex As Exception
  353. SendExternalSystemMessage("ERR: " & ex.Message)
  354. ' We're finished.
  355. ReDim SystemBytesToBeSent(blockSize - 1)
  356. SendingFile = False
  357. fileReader.Close()
  358. End Try
  359. End If
  360. End Sub
  361. Private Function GetFilenameFromPath(ByVal filePath As String) As String
  362. Dim filePathParts() As String
  363. If filePath.Trim = "" Then Return ""
  364. filePathParts = Split(filePath, "\")
  365. GetFilenameFromPath = filePathParts(filePathParts.Length - 1)
  366. End Function
  367. Private Sub HandleIncomingSystemMessages(ByVal bytes() As Byte, ByVal channel As Int32)
  368. If channel = 254 Then ' Text commands / messages passed between server and client
  369. Dim message As String = BytesToString(bytes)
  370. Dim tmp As String = ""
  371. Dim filePath As String
  372. ' Get File Request: The client wants us to send them a file.
  373. If message.Length > 4 Then tmp = message.Substring(0, 4)
  374. If tmp = "GFR:" Then ' Get File Request
  375. ' Get file path...
  376. filePath = message.Substring(4, message.Length - 4)
  377. ' Does it exist?
  378. If File.Exists(message.Substring(4, message.Length - 4)) Then
  379. ' Are we already busy sending them a file?
  380. If Not SendingFile Then
  381. Dim _theFilesInfo As New FileInfo(filePath)
  382. outgoingFileName = GetFilenameFromPath(filePath)
  383. outgoingFileSize = CULng(_theFilesInfo.Length)
  384. If BeginFileSend(filePath, _theFilesInfo.Length) Then
  385. ' Send only the file NAME. It will have a different path on the other side.
  386. SendExternalSystemMessage("Sending:" & outgoingFileName & _
  387. ":" & outgoingFileSize.ToString)
  388. SystemMessage("Sending file:" & outgoingFileName)
  389. Else
  390. ' FilePath contains the error message.
  391. SendExternalSystemMessage("ERR: " & filePath)
  392. End If
  393. Else
  394. ' There's already a GFR in progress.
  395. SendExternalSystemMessage("ERR: File: ''" & _
  396. FileBeingSentPath & _
  397. "'' is still in progress. Only one file " & _
  398. "may be transfered (from client to server) at a time.")
  399. End If
  400. Else
  401. ' File doesn't exist. Send an error.
  402. SendExternalSystemMessage("ERR: The requested file can not be found by the server.")
  403. End If
  404. End If
  405. If message.Length > 7 Then tmp = message.Substring(0, 8)
  406. If tmp = "Sending:" Then
  407. ' Strip away the headder...
  408. Dim msgParts() As String = Split(message, ":")
  409. IncomingFileSize = Convert.ToInt64(msgParts(2))
  410. IncomingFileName = msgParts(1)
  411. tmp = ReceivedFilesFolder & "\" & IncomingFileName
  412. SystemMessage("Receiving file: " & IncomingFileName)
  413. If Not BeginToReceiveAFile(tmp) Then
  414. SystemMessage("ERR: " & tmp)
  415. SendExternalSystemMessage("Abort<-")
  416. End If
  417. End If
  418. If message.Length > 10 Then tmp = message.Substring(0, 10)
  419. If tmp = "blocksize:" Then
  420. Dim msgParts() As String = Split(message, ":")
  421. blockSize = Convert.ToUInt16(msgParts(1))
  422. End If
  423. If message = "->Done" Then
  424. FinishReceivingTheFile()
  425. SystemMessage("->Done")
  426. End If
  427. ' We've been notified that no file data will be forthcoming.
  428. If message = "Abort->" Then
  429. FinishReceivingTheFile()
  430. SystemMessage("->Aborted.")
  431. Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Normal
  432. Try
  433. File.Delete(ReceivedFilesFolder & "\" & IncomingFileName)
  434. Catch ex As Exception
  435. End Try
  436. End If
  437. ' Notification that the server has complied with our
  438. ' request to stop sending bytes for this
  439. ' (server->client) file transfer.
  440. If message = "->Aborted." Then
  441. SystemMessage("->Aborted.")
  442. WrapUpIncomingFile()
  443. End If
  444. ' Notification that the server has complied with our
  445. ' request to stop recieving bytes for this
  446. ' (client->server) file transfer.
  447. If message = "<-Aborted." Then
  448. SystemMessage("<-Aborted.")
  449. End If
  450. If message.Length > 4 Then tmp = message.Substring(0, 4)
  451. If tmp = "ERR:" Then ' The server has sent us an error message.
  452. ' Pass it on up to the user.
  453. SystemMessage(message)
  454. End If
  455. ElseIf channel = 253 Then ' File transfer from server to client
  456. Try
  457. If ReceivingFile Then
  458. HandleIncomingFileBytes(bytes)
  459. fileBytesRecieved += bytes.LongLength
  460. End If
  461. Catch ex As Exception
  462. End Try
  463. ElseIf channel = 252 Then ' File transfer from client to server
  464. ElseIf channel = 251 Then ' reserved.
  465. End If
  466. End Sub
  467. Private Function HandleOutgoingInternalSystemMessage() As Boolean
  468. Dim tmp(1) As Byte
  469. HandleOutgoingInternalSystemMessage = False
  470. Dim _size As Integer
  471. GetMoreFileBytesIfAvailable()
  472. ' Handle outgoing system stuff here
  473. If SystemBytesToBeSentAvailable = True Then
  474. HandleOutgoingInternalSystemMessage = True
  475. If SystemBytesToBeSent.Length > blockSize Then
  476. ' Send Channel
  477. tmp(0) = SystemOutputChannel
  478. Stream.Write(tmp, 0, 1)
  479. bytesSentThisSecond += 1
  480. ' Send packet size
  481. _size = blockSize
  482. tmp = BitConverter.GetBytes(_size)
  483. Stream.Write(tmp, 0, 2)
  484. bytesSentThisSecond += 2
  485. ' Send packet
  486. Stream.Write(GetSome(SystemBytesToBeSent, blockSize, SystemBytesToBeSentAvailable), 0, _size)
  487. bytesSentThisSecond += _size
  488. Else
  489. ' Send Channel
  490. tmp(0) = SystemOutputChannel
  491. Stream.Write(tmp, 0, 1)
  492. bytesSentThisSecond += 1
  493. ' Send packet size
  494. _size = SystemBytesToBeSent.Length
  495. tmp = BitConverter.GetBytes(_size)
  496. Stream.Write(tmp, 0, 2)
  497. bytesSentThisSecond += 2
  498. ' Send packet
  499. Stream.Write(SystemBytesToBeSent, 0, _size)
  500. bytesSentThisSecond += _size
  501. SystemBytesToBeSentAvailable = False
  502. End If
  503. End If
  504. End Function
  505. Private Function HandleOutgoingUserData() As Boolean
  506. Dim tmp(1) As Byte
  507. Dim _size As UShort
  508. Dim notify As Boolean = False
  509. Static packet(0) As Byte
  510. If UserBytesToBeSentAvailable = True Then
  511. SyncLock UserBytesToBeSent
  512. Try
  513. If (UserBytesToBeSent.Length - UserBytesToBeSent.Position) > blockSize Then
  514. ' Send Channel
  515. tmp(0) = UserOutputChannel
  516. Stream.Write(tmp, 0, 1)
  517. ' Send packet size
  518. _size = blockSize
  519. tmp = BitConverter.GetBytes(_size)
  520. Stream.Write(tmp, 0, 2)
  521. ' Send packet
  522. If packet.Length <> _size Then ReDim packet(_size - 1)
  523. UserBytesToBeSent.Read(packet, 0, _size)
  524. 'Client.NoDelay = True
  525. Stream.Write(packet, 0, _size)
  526. bytesSentThisSecond += 3 + _size
  527. ' Check to see if we've sent it all...
  528. If UserBytesToBeSent.Length = UserBytesToBeSent.Position Then
  529. UserBytesToBeSentAvailable = False
  530. notify = True
  531. End If
  532. Else
  533. ' Send Channel
  534. tmp(0) = UserOutputChannel
  535. Stream.Write(tmp, 0, 1)
  536. ' Send packet size
  537. _size = Convert.ToUInt16(UserBytesToBeSent.Length - UserBytesToBeSent.Position)
  538. tmp = BitConverter.GetBytes(_size)
  539. Stream.Write(tmp, 0, 2)
  540. ' Send packet
  541. If packet.Length <> _size Then ReDim packet(_size - 1)
  542. UserBytesToBeSent.Read(packet, 0, _size)
  543. 'Client.NoDelay = True
  544. Stream.Write(packet, 0, _size)
  545. bytesSentThisSecond += 3 + _size
  546. UserBytesToBeSentAvailable = False
  547. notify = True
  548. End If
  549. Catch ex As Exception
  550. ' Report error attempting to send user data.
  551. Debug.WriteLine("Unexpected error in TcpCommClient\HandleOutgoingUserData: " & ex.Message)
  552. End Try
  553. End SyncLock
  554. ' Notify the user that the packet has been sent.
  555. If notify Then SystemMessage("UBS:" & UserOutputChannel)
  556. Return True
  557. Else
  558. Return False
  559. End If
  560. End Function
  561. 'Private Function HandleOutgoingUserData() As Boolean
  562. ' Dim tmp(1) As Byte
  563. ' Dim _size As UShort
  564. ' If UserBytesToBeSentAvailable = True Then
  565. ' SyncLock UserBytesToBeSent.SyncRoot
  566. ' If UserBytesToBeSent.Length > blockSize Then
  567. ' ' Send Channel
  568. ' tmp(0) = UserOutputChannel
  569. ' Stream.Write(tmp, 0, 1)
  570. ' bytesSentThisSecond += 1
  571. ' ' Send packet size
  572. ' _size = blockSize
  573. ' tmp = BitConverter.GetBytes(_size)
  574. ' Stream.Write(tmp, 0, 2)
  575. ' bytesSentThisSecond += 2
  576. ' ' Send packet
  577. ' Stream.Write(GetSome(UserBytesToBeSent, blockSize, UserBytesToBeSentAvailable, True), 0, _size)
  578. ' bytesSentThisSecond += _size
  579. ' Else
  580. ' ' Send Channel
  581. ' tmp(0) = UserOutputChannel
  582. ' Stream.Write(tmp, 0, 1)
  583. ' bytesSentThisSecond += 1
  584. ' ' Send packet size
  585. ' _size = UserBytesToBeSent.Length
  586. ' tmp = BitConverter.GetBytes(_size)
  587. ' Stream.Write(tmp, 0, 2)
  588. ' bytesSentThisSecond += 2
  589. ' ' Send packet
  590. ' Stream.Write(UserBytesToBeSent, 0, _size)
  591. ' bytesSentThisSecond += _size
  592. ' UserBytesToBeSentAvailable = False
  593. ' SystemMessage("UBS")
  594. ' End If
  595. ' End SyncLock
  596. ' Return True
  597. ' Else
  598. ' Return False
  599. ' End If
  600. 'End Function
  601. Private Function GetSome(ByRef bytes() As Byte, ByVal chunkToBreakOff As Integer, _
  602. ByRef bytesToBeSentAvailable As Boolean, _
  603. Optional ByVal theseAreUserBytes As Boolean = False) As Byte()
  604. Dim tmp(chunkToBreakOff - 1) As Byte
  605. Array.Copy(bytes, 0, tmp, 0, chunkToBreakOff)
  606. GetSome = tmp
  607. If bytes.Length = chunkToBreakOff Then
  608. bytesToBeSentAvailable = False
  609. If theseAreUserBytes Then SystemMessage("UBS")
  610. Else
  611. Dim tmp2(bytes.Length - chunkToBreakOff - 1) As Byte
  612. Array.Copy(bytes, chunkToBreakOff, tmp2, 0, bytes.Length - chunkToBreakOff)
  613. bytes = tmp2
  614. End If
  615. End Function
  616. Private Sub SystemMessage(ByVal MsgText As String)
  617. RcvBytes(StrToByteArray(MsgText), 255)
  618. End Sub
  619. ' Check to see if our app is closing (set in FormClosing event)
  620. Private Function theClientIsStopping() As Boolean
  621. If continue_running = False Then
  622. theClientIsStopping = True
  623. Else
  624. theClientIsStopping = False
  625. End If
  626. End Function
  627. Private Function CalculateMbps(Optional ByVal GetMbps As Boolean = False) As Decimal
  628. Static averagesCounter As Integer = 0
  629. Static tmr As Date = Now
  630. Static lastread As Int32 = 0
  631. Dim looper As Short = 0
  632. Dim tmp As Int32 = 0
  633. If mbpsOneSecondAverage Is Nothing Then ReDim mbpsOneSecondAverage(9)
  634. If Now >= tmr.AddMilliseconds(250) Then
  635. averagesCounter += 1
  636. If averagesCounter < 0 Then averagesCounter = 0
  637. Select Case averagesCounter
  638. Case 0
  639. SyncLock (mbpsSyncObject)
  640. Try
  641. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  642. bytesSentThisSecond = 0
  643. bytesReceivedThisSecond = 0
  644. Catch ex As Exception
  645. averagesCounter = -1
  646. End Try
  647. End SyncLock
  648. Case 1
  649. SyncLock (mbpsSyncObject)
  650. Try
  651. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  652. bytesSentThisSecond = 0
  653. bytesReceivedThisSecond = 0
  654. Catch ex As Exception
  655. averagesCounter = -1
  656. End Try
  657. End SyncLock
  658. Case 2
  659. SyncLock (mbpsSyncObject)
  660. Try
  661. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  662. bytesSentThisSecond = 0
  663. bytesReceivedThisSecond = 0
  664. Catch ex As Exception
  665. averagesCounter = -1
  666. End Try
  667. End SyncLock
  668. Case 3
  669. SyncLock (mbpsSyncObject)
  670. Try
  671. mbpsOneSecondAverage(averagesCounter) = bytesSentThisSecond + bytesReceivedThisSecond
  672. bytesSentThisSecond = 0
  673. bytesReceivedThisSecond = 0
  674. Catch ex As Exception
  675. averagesCounter = -1
  676. End Try
  677. End SyncLock
  678. End Select
  679. If averagesCounter > 2 Then averagesCounter = -1
  680. tmr = Now
  681. End If
  682. ' Did they ask us for the Mbps?
  683. If GetMbps Then
  684. For looper = 0 To 3
  685. SyncLock (mbpsSyncObject)
  686. tmp += mbpsOneSecondAverage(looper)
  687. End SyncLock
  688. Next
  689. CalculateMbps = tmp
  690. Else
  691. CalculateMbps = 0
  692. End If
  693. End Function
  694. Private Sub Run()
  695. Dim puck(1) As Byte : puck(0) = 0
  696. Dim theBuffer(blockSize - 1) As Byte
  697. Dim tmp(1) As Byte
  698. Dim dataChannel As Integer = 0
  699. Dim packetSize As UShort = 0
  700. Dim bytesread As Integer
  701. Dim userOrSystemSwitcher As Integer = 0
  702. Dim PercentUsage As Short = -1
  703. Dim connectionLossTimer As Date
  704. Dim CPUutil As New CpuMonitor
  705. CPUutil.Start
  706. Try
  707. Client = New TcpClient
  708. Client.Connect(IP, Port)
  709. ' Connection Accepted.
  710. Stream = Client.GetStream()
  711. ' Set the send and receive buffers to the maximum
  712. ' size allowable in this application...
  713. Client.Client.ReceiveBufferSize = 65535
  714. Client.Client.SendBufferSize = 65535
  715. ' no delay on partially filled packets...
  716. ' Send it all as fast as possible.
  717. Client.NoDelay = True
  718. ' Pass a message up to the user about our status.
  719. SystemMessage("Connected.")
  720. isRunning = True
  721. ' Start the communication loop
  722. Do
  723. ' Check to see if our app is shutting down.
  724. If theClientIsStopping() Then Exit Do
  725. ' Normal communications...
  726. If weHaveThePuck Then
  727. ' Send user data if there is any to be sent.
  728. userOrSystemSwitcher += 1
  729. Select Case userOrSystemSwitcher
  730. Case 1
  731. HandleOutgoingUserData()
  732. Case 2
  733. HandleOutgoingInternalSystemMessage()
  734. End Select
  735. If userOrSystemSwitcher > 1 Then userOrSystemSwitcher = 0
  736. ' After sending our data, send the puck
  737. Stream.Write(puck, 0, 1)
  738. ' Uncomment this to see control bit traffic as part of your Mbps
  739. 'bytesSentThisSecond += 1
  740. weHaveThePuck = False
  741. End If
  742. If theBuffer.Length < 2 Then ReDim theBuffer(1)
  743. ' Read in the control byte.
  744. Stream.Read(theBuffer, 0, 1)
  745. dataChannel = theBuffer(0)
  746. ' Uncomment this to see control bit traffic as part of your Mbps
  747. 'bytesReceivedThisSecond += 1
  748. ' If it's just the puck (communictaion syncronization byte),
  749. ' set weHaveThePuck true and that's all. dataChannel 0 is
  750. ' reserved for the puck.
  751. If dataChannel = 0 Then
  752. weHaveThePuck = True
  753. Else
  754. ' It's not the puck: It's an incoming packet.
  755. ' Get the packet size:
  756. tmp(0) = Convert.ToByte(Stream.ReadByte)
  757. tmp(1) = Convert.ToByte(Stream.ReadByte)
  758. packetSize = BitConverter.ToUInt16(tmp, 0)
  759. If theBuffer.Length <> packetSize Then ReDim theBuffer(packetSize - 1)
  760. bytesReceivedThisSecond += 2
  761. ' Get the packet:
  762. connectionLossTimer = Now
  763. Do
  764. ' Check to see if we're stopping...
  765. If theClientIsStopping() Then Exit Do
  766. ' Read bytes in...
  767. bytesread += Stream.Read(theBuffer, bytesread, (packetSize - bytesread))
  768. ' If it takes longer then 3 seconds to get a packet, we've lost connection.
  769. If connectionLossTimer.AddSeconds(3) < Now Then Exit Try
  770. Loop While bytesread < packetSize
  771. bytesread = 0
  772. ' Record bytes read for throttling...
  773. bytesReceivedThisSecond += packetSize
  774. ' Handle the packet...
  775. If dataChannel > 250 Then
  776. ' this is an internal system packet
  777. HandleIncomingSystemMessages(theBuffer, dataChannel)
  778. Else
  779. ' Hand data off to the calling thread.
  780. RcvBytes(theBuffer, dataChannel)
  781. End If
  782. If theClientIsStopping() Then Exit Do
  783. End If
  784. CalculateMbps(False)
  785. ' Measure and display the CPU usage of the client (this thread).
  786. If PercentUsage <> CPUutil.ThreadUsage Then
  787. PercentUsage = CPUutil.ThreadUsage
  788. SystemMessage("" & PercentUsage & "% Thread Usage (" & CPUutil.CPUusage & "% across all CPUs)")
  789. End If
  790. Loop
  791. Catch ex As Exception
  792. ' An unexpected error.
  793. Debug.WriteLine("Unexpected error in Client\Run: " & ex.Message)
  794. End Try
  795. Try
  796. fileWriter.Close()
  797. Catch ex As Exception
  798. End Try
  799. Try
  800. CPUutil.StopWatcher()
  801. Client.Client.Close()
  802. SystemMessage("Disconnected.")
  803. Catch ex As Exception
  804. ' An unexpected error.
  805. Debug.WriteLine("Unexpected error in Client\theClientIsStopping: " & ex.Message)
  806. End Try
  807. WrapUpIncomingFile()
  808. isRunning = False
  809. End Sub
  810. End Class