藉助TCP完成文件的傳輸,基本思路以下:html
因爲文件傳輸須要穩定可靠的鏈接,因此採用TCP方式完成網絡文件傳輸功能。編程
首先獲取文件名。藉助os包中的stat()函數來獲取文件屬性信息。在函數返回的文件屬性中包含文件名和文件大小。Stat參數name傳入的是文件訪問的絕對路徑。FileInfo中的Name()函數能夠將文件名單獨提取出來。服務器
func Stat(name string) (fi FileInfo, err error)
Stat返回一個描述name指定的文件對象的FileInfo。若是指定的文件對象是一個符號連接,返回的FileInfo描述該符號連接指向的文件的信息,本函數會嘗試跳轉該連接。若是出錯,返回的錯誤值爲*PathError類型。網絡
咱們經過源碼能夠得知FileInfo是一個接口,要實現這個接口就必須實現這個接口的以下全部方法socket
實現網絡文件傳輸實質上時藉助了本地文件複製和TCP網絡編程相關知識,能夠先看看Go語言複製文件和Go網絡編程瞭解相關內容。tcp
因此關於使用TCP實現文件傳輸大體步驟能夠歸結爲以下步驟函數
接收端:命令行
接收端代碼:3d
package main import ( "fmt" "io" "net" "os" ) func recvFile(conn net.Conn, fileName string) { //按照文件名建立新文件 file, err := os.Create(fileName) if err != nil { fmt.Printf("os.Create()函數執行錯誤,錯誤爲:%v\n", err) return } defer file.Close() //從網絡中讀數據,寫入本地文件 for { buf := make([]byte, 4096) n, err := conn.Read(buf) //寫入本地文件,讀多少,寫多少 file.Write(buf[:n]) if err != nil { if err == io.EOF { fmt.Printf("接收文件完成。\n") } else { fmt.Printf("conn.Read()方法執行出錯,錯誤爲:%v\n", err) } return } } } func main() { //1.建立監聽socket listener, err := net.Listen("tcp", "127.0.0.1:8000") if err != nil { fmt.Printf("net.Listen()函數執行錯誤,錯誤爲:%v\n", err) return } defer listener.Close() //阻塞監聽 conn, err := listener.Accept() if err != nil { fmt.Printf("listener.Accept()方法執行錯誤,錯誤爲:%v\n", err) return } defer conn.Close() //文件名的長度不能超過1024個字節 buf := make([]byte, 4096) n, err := conn.Read(buf) if err != nil { fmt.Printf("conn.Read()方法執行錯誤,錯誤爲:%v\n", err) return } fileName := string(buf[:n]) //回寫ok給發送端 conn.Write([]byte("ok")) //獲取文件內容 recvFile(conn, fileName) }
發送端:code
發送端代碼:
package main import ( "fmt" "io" "net" "os" ) func sendFile(conn net.Conn, filePath string) { //只讀打開文件 file, err := os.Open(filePath) if err != nil { fmt.Printf("os.Open()函數執行出錯,錯誤爲:%v\n", err) return } defer file.Close() buf := make([]byte, 4096) for { //從本地文件中讀數據,寫給網絡接收端。讀多少,寫多少 n, err := file.Read(buf) if err != nil { if err == io.EOF { fmt.Printf("發送文件完畢\n") } else { fmt.Printf("file.Read()方法執行錯誤,錯誤爲:%v\n", err) } return } //寫到網絡socket中 _, err = conn.Write(buf[:n]) } } func main() { //獲取命令行參數 list := os.Args if len(list) != 2 { fmt.Printf("格式爲:go run xxx.go 文件名\n") return } //提取文件的絕對路徑 path := list[1] //獲取文件屬性 fileInfo, err := os.Stat(path) if err != nil { fmt.Printf("os.Stat()函數執行出錯,錯誤爲:%v\n", err) return } //主動發起鏈接請求 conn, err := net.Dial("tcp", "127.0.0.1:8000") if err != nil { fmt.Printf("net.Dial()函數執行出錯,錯誤爲:%v\n", err) return } defer conn.Close() //發送文件名給接收端 _, err = conn.Write([]byte(fileInfo.Name())) //讀取服務器回發數據 buf := make([]byte, 4096) n, err := conn.Read(buf) if err != nil { fmt.Printf("conn.Read(buf)方法執行出錯,錯誤爲:%v\n", err) return } if string(buf[:n]) == "ok" { //寫文件內容給服務器 -- 藉助conn sendFile(conn, path) } }