TransferFile.vb
Imports System.SerializableAttribute
<Serializable()> Public Class TransferFile
Public FileName As String
Public Data() As Byte
End Class
TcpFileReceiver.vb
Imports System.Net.Sockets
Imports System.Net
Imports System.IO
Imports System.Threading
Imports System.SerializableAttribute
Imports System.Runtime.Serialization.Formatters.Binary
Public Class TcpFileReceiver
' 預設寫入檔案資料夾
Public SavePath As String = AppDomain.CurrentDomain.BaseDirectory
' 監聽器
Private fileListener As TcpListener
' 暫存資料
Private tempData As Dictionary(Of String, List(Of Byte))
Public Sub New(ByVal ip As IPAddress, ByVal port As Integer)
Me.fileListener = New TcpListener(New IPEndPoint(ip, port))
Me.tempData = New Dictionary(Of String, List(Of Byte))
End Sub
' 開始監聽
Public Sub Start()
Me.fileListener.Start()
' 建立接收連線的執行緒
Dim listenThread As Thread = New Thread(New ThreadStart(AddressOf DeterminConnection))
listenThread.IsBackground = True
listenThread.Start()
End Sub
' 結束監聽
Public Sub StopListen()
Me.fileListener.Stop()
End Sub
' 偵測client端連接
Private Sub DeterminConnection()
Do
Try
' 如果有連接
If Me.fileListener.Pending Then
' 建立傳輸的執行緒
Dim receiveThread As Thread = New Thread(New ThreadStart(AddressOf StartServerListener))
receiveThread.IsBackground = True
receiveThread.Start()
End If
Catch ex As Exception
' do something
End Try
GC.Collect()
Thread.Sleep(1000)
Loop
End Sub
' 起始傳輸
Private Sub StartServerListener()
Do
Try
' 建立傳輸通道
Dim rSocket As Socket = Me.fileListener.AcceptSocket()
If rSocket.Connected Then
' 接收連線的buffer
Dim rBuffer(1024) As Byte
' 暫存資料的key
Dim rGuid As String = Guid.NewGuid.ToString
' 開始接收
SyncLock rSocket
rSocket.BeginReceive(rBuffer, 0, 1024, SocketFlags.None, AddressOf GetData, New Object() {rSocket, rBuffer, rGuid})
End SyncLock
End If
Catch ex As Exception
Return
End Try
Loop
End Sub
Private Sub GetData(ByVal result As IAsyncResult)
Try
' 目前傳輸的socket
Dim rSocket As Socket = CType(result.AsyncState, Object())(0)
' 接收的資料
Dim rBuffer() As Byte = CType(result.AsyncState, Object())(1)
' 暫存資料的key
Dim rGuid As String = CType(result.AsyncState, Object())(2)
' 如果沒有資料, 建立暫存區
If Not Me.tempData.ContainsKey(rGuid) Then
Me.tempData.Add(rGuid, New List(Of Byte))
End If
' 讀取的總數
Dim readed As Integer = rSocket.EndReceive(result)
If readed > 0 Then
'Dim data As List(Of Byte) = tempData(rGuid)
'For i As Integer = 0 To readed - 1
' Me.tempData(rGuid).Add(rBuffer(i))
'Next
' 存入暫存區
Array.Resize(rBuffer, readed)
Me.tempData(rGuid).AddRange(rBuffer)
' 讀取下一段資料
ReDim rBuffer(1024)
SyncLock rSocket
rSocket.BeginReceive(rBuffer, 0, 1024, SocketFlags.None, AddressOf GetData, New Object() {rSocket, rBuffer, rGuid})
End SyncLock
Else
rSocket = Nothing
rBuffer = Nothing
' 反序列化
Dim transferObj As TransferFile = Me.Deserialize(Me.tempData(rGuid).ToArray)
' 存檔
File.WriteAllBytes(Me.SavePath & transferObj.FileName, transferObj.Data)
' 移除暫存資料
Me.tempData(rGuid).Clear()
Me.tempData.Remove(rGuid)
rGuid = Nothing
' 資源回收
GC.Collect()
End If
Catch ex As Exception
' do something
End Try
End Sub
' 反序列化
Private Function Deserialize(ByRef data() As Byte) As TransferFile
Dim ms As MemoryStream = New MemoryStream(data)
Dim formater As BinaryFormatter = New BinaryFormatter
Dim transferObj As TransferFile = formater.Deserialize(ms)
ms.Close()
Return transferObj
End Function
End Class
TcpFileSender.vb
Imports System.IO
Imports System.Net.Sockets
Imports System.Net
Imports System.Threading
Imports System.SerializableAttribute
Imports System.Runtime.Serialization.Formatters.Binary
Public Class TcpFileSender
Private client As TcpClient
Public Sub New()
Me.client = New TcpClient()
End Sub
Public Function ConnectServer(ByVal ip As IPAddress, ByVal port As Integer) As Boolean
Try
' 連接至server
Me.client.Connect(New IPEndPoint(ip, port))
Return True
Catch ex As Exception
Return False
End Try
End Function
Public Sub CloseConnection()
Me.client.Close()
GC.Collect()
End Sub
Public Sub Send(ByVal filepath As String)
Dim thread As Thread = New Thread(New ParameterizedThreadStart(AddressOf SendFile))
thread.IsBackground = True
thread.Start(filepath)
End Sub
Public Sub SendFile(ByVal filepath As String)
' 檔案不存在
If Not File.Exists(filepath) Then
Throw New FileNotFoundException
End If
' 建立要傳送的物件實體
Dim transferObj As TransferFile = New TransferFile
' 取檔名
Dim inputFile As FileInfo = New FileInfo(filepath)
transferObj.FileName = inputFile.Name
' 讀取檔案
Dim inputStream As FileStream = New FileStream(filepath, FileMode.Open)
ReDim transferObj.Data(inputStream.Length)
inputStream.Read(transferObj.Data, 0, transferObj.Data.Length)
inputStream.Close()
' 序列化
Dim transferData() As Byte = Me.Serialize(transferObj)
If Me.client.Connected Then
' 防止檔案過大, 佇列已滿
While True
Try
Me.client.GetStream.Write(transferData, 0, transferData.Length)
GC.Collect()
Exit While
Catch ex As Exception
Threading.Thread.Sleep(1000)
End Try
End While
Else
Throw New Exception("Not Connected!")
End If
End Sub
' 序列化物件
Private Function Serialize(ByVal obj As Object) As Byte()
Dim ms As MemoryStream = New MemoryStream
Dim formater As BinaryFormatter = New BinaryFormatter
formater.Serialize(ms, obj)
Dim data() As Byte = ms.GetBuffer
ms.Close()
Return data
End Function
End Class