2010年12月7日 星期二

vbnet socket 傳檔+續傳

來源處

---
主機端:
' 宣告儲存二進位檔案通道編號的變數
Dim FileNo As Integer
' 儲存接收檔案的檔案名稱變數
Dim RecvFileName As String

Private Sub Form_Load()
' 初始化各種控制項的相關屬性值
Label2.Caption = "接收位元組"
Label3.Caption = "0"
Me.Caption = "EX1004 主機端"
Timer1.Interval = 100

' 初始化二組Winsock控制項
' Winsock1用來傳送溝通訊息
Winsock1.Protocol = sckTCPProtocol
Winsock1.LocalPort = 6000
Winsock1.Listen
' Winsock2用來傳送檔案內容
Winsock2.Protocol = sckTCPProtocol
Winsock2.LocalPort = Winsock1.LocalPort + 1
Winsock2.Listen
End Sub

Private Sub Timer1_Timer()
' 判斷Winsock控制項的狀態
Select Case Winsock1.State
Case sckClosed ' 常數值0
Label1.Caption = "已經關閉用戶端連線"
Case sckOpen ' 常數值1
Label1.Caption = "開啟"
Case sckListening ' 常數值2
Label1.Caption = "監聽中..."
Case sckConnectionPending ' 常數值3
Label1.Caption = "尚未連連線"
Case sckResolvingHost ' 常數值4
Label1.Caption = "主機解析中"
Case sckHostResolved ' 常數值5
Label1.Caption = "主機解析完畢"
Case sckConnecting ' 常數值6
Label1.Caption = "連線中..."
Case sckConnected ' 常數值7
Label1.Caption = "已經連線"
Case sckClosing ' 常數值8
Label1.Caption = "正在關閉連線"
' 判斷Winsock控制項的連線狀態
If Winsock1.State <> sckClosed Then
' 關閉Winsock1控制項現有的連線作業
Winsock1.Close
DoEvents
' 將Winsock1控制項設定在監聽模式
Winsock1.Listen
' 關閉Winsock2控制項現有的連線作業
Winsock2.Close
DoEvents
Winsock2.Listen
End If
End Select
End Sub

Private Sub Winsock1_ConnectionRequest(ByVal RequestID As Long)
If Winsock1.State <> sckClosed Then Winsock1.Close
' 允許遠端設備使用必要的識別碼(RequestID)與主機
' 進行連接。
Winsock1.Accept RequestID
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim sVar As String
Dim OldLength As Long
Dim FileNo1 As Integer
Dim Buffers() As Byte
Winsock1.GetData sVar, vbString
Select Case Mid(sVar, 1, 4)
' 用戶端傳來檔案名稱表示準備傳送檔案,
' 並等候主機端的回應
Case "檔案名稱"
' 檔案名稱文字之後,即為即將接收的檔案名稱
RecvFileName = Mid(sVar, 5)
If Len(Dir$(RecvFileName)) > 0 Then
' 檔案存在
OldLength = FileLen(RecvFileName)
Name App.Path & "\" & RecvFileName As App.Path & "\TEMP.BIN"
DoEvents
End If
' 重新設定顯示接收位元組的Label3控制項
Label3.Caption = "0"
' 取得可用的檔案通道
FileNo = FreeFile
' 以二進位檔案寫入模式,開啟指定的檔案開啟
Open App.Path & "\" & RecvFileName For Binary Access Write As #FileNo
' 依據 OldLength變數的值,判斷是否需要續傳
If OldLength > 0 Then
FileNo1 = FreeFile
' 開啟暫存檔
Open App.Path & "\TEMP.BIN" For Binary Access Read As #FileNo1
' 將暫存檔的內容全數讀入緩衝區位元組陣列
ReDim Buffers(OldLength - 1)
Get #FileNo1, , Buffers
DoEvents
' 將暫存檔的內容寫入即將續傳的檔案中
Put #FileNo, , Buffers
Close #FileNo1
DoEvents
' 刪除暫存檔
Kill App.Path & "\TEMP.BIN"
DoEvents
' 回傳『斷點續傳』訊息 + 已經接收的檔案位元組數量
Winsock1.SendData "斷點續傳" & OldLength
Else
' 回傳主機端已經開啟二進位檔案的寫入模式
Winsock1.SendData "準備就緒"
End If
Case "傳送檔案"
Label1.Caption = "傳送檔案"
Case "傳送完畢"
' 關閉已經開啟的通道
Close #FileNo
FileNo = 0
' 回傳主機端已經接收完畢
Winsock1.SendData "資料接收完畢"
DoEvents
End Select
End Sub

Private Sub Winsock2_ConnectionRequest(ByVal RequestID As Long)
If Winsock2.State <> sckClosed Then Winsock2.Close
' 允許遠端設備使用必要的識別碼(RequestID)與主機
' 進行連接。
Winsock2.Accept RequestID
End Sub

Private Sub Winsock2_DataArrival(ByVal bytesTotal As Long)
Dim sVar() As Byte
' 從 FileNo變數的值,可以判定二進位檔案寫入模式是否已經準備就緒
If FileNo > 0 Then
' 讀取 Winsock2 控制項的接收緩衝區
Winsock2.GetData sVar, vbByte
' 將位元組陣列寫入檔案
Put #FileNo, , sVar
Winsock1.SendData "資料接收中"
' 更新已經接收位元組數量的資訊
Label3.Caption = CLng(Label3.Caption) + UBound(sVar, 1) + 1
End If
End Sub



---
用戶端(用來傳送檔案):
' 宣告用來儲存將要傳送檔案名稱的變數
Dim SendFileName As String

' 按下『連線』按鈕
Private Sub Command1_Click()
' 關閉 Winsock1、Winsock2控制項的目前連線
If Winsock1.State <> sckClosed Then
Winsock1.Close
End If
If Winsock2.State <> scckclosed Then
Winsock2.Close
End If
' 初始化Winsock1控制項和Winsock2控制項
Winsock1.Protocol = sckTCPProtocol
Winsock1.RemoteHost = Text1.Text
Winsock1.RemotePort = CLng(Text2.Text)
Winsock2.Protocol = sckTCPProtocol
Winsock2.RemoteHost = Text1.Text
Winsock2.RemotePort = CLng(Text2.Text) + 1
' 和主機端連接
Winsock1.Connect
Winsock2.Connect
End Sub

' 按下『離線』按鈕
Private Sub Command2_Click()
Winsock1.Close
Winsock2.Close
End Sub

Private Sub Command3_Click()
' 宣告即將取出檔案名稱的變數
Dim Datas() As String
CommonDialog1.Filter = "所有檔案(*.*)|*.*"
CommonDialog1.InitDir = "C:\"
CommonDialog1.ShowOpen
' 判斷 FileName 屬性值是否空白
If Trim(CommonDialog1.FileName) = "" Then
Exit Sub
End If
' 設定 SendFileName變數的值
SendFileName = CommonDialog1.FileName
' 將 SendFileName變數的值 暫存在 Label3控制項的Tag屬性
Label3.Tag = "『" & SendFileName & "』"
' 取出不含路徑資訊的檔案名稱
Datas = Split(SendFileName, "\")
' 傳送即將傳送的檔案名稱
Winsock1.SendData "檔案名稱" & Datas(UBound(Datas, 1))
DoEvents
End Sub

Private Sub Form_Load()
' 初始化各種控制項的相關屬性
Label1.Caption = "主機位址:"
Label2.Caption = "連接埠編號:"
Label3.Caption = ""
Me.Caption = "EX1004 用戶端"
Command1.Caption = "連線"
Command2.Caption = "離線"
Command3.Caption = "傳送檔案"
Text1.Text = "127.1"
Text2.Text = "6000"
' 啟用 Timer1控制項監視Winsock1控制項的狀態
Timer1.Interval = 100
End Sub

Private Sub Timer1_Timer()
' 判斷Winsock控制項的狀態
Select Case Winsock1.State
Case sckClosed ' 常數值0
Label4.Caption = "尚未連線"
Case sckOpen ' 常數值1
Label4.Caption = "開啟"
Case sckListening ' 常數值2
Label4.Caption = "監聽中..."
Case sckConnectionPending ' 常數值3
Label4.Caption = "尚未連連線"
Case sckResolvingHost ' 常數值4
Label4.Caption = "主機解析中"
Case sckHostResolved ' 常數值5
Label4.Caption = "主機解析完畢"
Case sckConnecting ' 常數值6
Label4.Caption = "連線中..."
Case sckConnected ' 常數值7
Label4.Caption = "已經和主機端連線"
Case sckClosing ' 常數值8
Label4.Caption = "切斷連線中"
End Select
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim sVar
Dim TotalBytes As Long ' 取得檔案的位元組數量
Dim Buffers() As Byte ' 緩衝區位元組陣列
Dim I As Long ' 迴圈變數
Dim Mods As Long ' 取得餘數
Dim Quotient As Long ' 取得商
Dim FileNo As Integer ' 儲存檔案通道編號
Dim BreakPoint As Long ' 取得傳輸中斷點的位元組數量
Winsock1.GetData sVar, vbString
Select Case Trim(sVar)
Case "資料接收完畢"
Label3.Caption = Label3.Tag & "檔案接收完畢"
' 表示主機端已經開啟二進位檔案的寫入模式
Case "準備就緒"
Label3.Caption = Label3.Tag & "檔案傳送中..."
TotalBytes = FileLen(SendFileName)
' 假設每次讀取 1024個位元組
' 取得檔案位元組數量和 1024的餘數
Mods = TotalBytes Mod 1024 ' 取餘數
Quotient = Fix(TotalBytes / 1024) ' 取商數
FileNo = FreeFile ' 取得可用的檔案通道
ReDim Buffers(1023) ' 重新宣告位元組陣列的大小
Open SendFileName For Binary Access Read As #FileNo
' 執行迴圈讀取檔案內容
For I = 1 To Quotient
Get #FileNo, , Buffers ' 從檔案讀取位元組資料
DoEvents
Winsock2.SendData Buffers ' 傳送檔案的位元組資料
Next
' 處理最後的『第n部分』
If Mods <> 0 Then
' 餘數的數值即為最後需要傳送的位元組數量
ReDim Buffers(Mods - 1)
Get #FileNo, , Buffers ' 從檔案讀取剩餘的位元組資料
Winsock2.SendData Buffers ' 傳送檔案的位元組資料
DoEvents
End If
Close #FileNo
' 告訴主機端檔案已經傳送完畢
Winsock1.SendData "傳送完畢"
DoEvents
Case Else
If Mid(sVar, 1, 4) = "斷點續傳" Then
' 取得斷點位元組數量
BreakPoint = CLng(Mid(sVar, 5))
TotalBytes = FileLen(SendFileName) - BreakPoint
' 假設每次讀取 1024個位元組
' 取得檔案位元組數量和 1024的餘數
Mods = TotalBytes Mod 1024 ' 取餘數
Quotient = Fix(TotalBytes / 1024) ' 取商數
FileNo = FreeFile ' 取得可用的檔案通道
Open SendFileName For Binary Access Read As #FileNo
ReDim Buffers(BreakPoint - 1) ' 重新宣告位元組陣列的大小
Get #FileNo, , Buffers ' 讀取但不處理
DoEvents
ReDim Buffers(1023) ' 重新宣告位元組陣列的大小
' 執行迴圈讀取檔案內容
For I = 1 To Quotient
Get #FileNo, , Buffers ' 從檔案讀取位元組資料
Winsock2.SendData Buffers ' 傳送檔案的位元組資料
DoEvents
Next
' 處理最後的『第n部分』
If Mods <> 0 Then
' 餘數的數值即為最後需要傳送的位元組數量
ReDim Buffers(Mods - 1)
Get #FileNo, , Buffers ' 從檔案讀取剩餘的位元組資料
Winsock2.SendData Buffers ' 傳送檔案的位元組資料
DoEvents
End If
Close #FileNo
' 告訴主機端檔案已經傳送完畢
Winsock1.SendData "傳送完畢"
DoEvents
End If
End Select
End Sub

沒有留言:

張貼留言