服務端實現流程大致如下:
- 創建監聽listener,程序結束時關閉。
- 阻塞等待客戶端連接,程序結束時關閉conn。
- 讀取客戶端發送文件名。保存fileName。
- 回發“ok”給客戶端做應答
- 封裝函數 RecvFile接收客戶端發送的文件內容。傳參fileName 和conn
- 按文件名Create文件,結束時Close
- 循環Read客戶端發送的文件內容,當讀到EOF說明文件讀取完畢。
- 將讀到的內容原封不動Write到創建的文件中
package main import ( "fmt" "net" "os" "runtime" ) func Handler(conn net.Conn) { buf := make([]byte, 2048) //讀取客戶端發送的內容 n, err := conn.Read(buf) if err != nil { fmt.Println(err) return } fileName := string(buf[:n]) //獲取客戶端ip+port addr := conn.RemoteAddr().String() fmt.Println(addr + ": 客戶端傳輸的文件名為--" + fileName) //告訴客戶端已經接收到文件名 conn.Write([]byte("ok")) //創建文件 f, err := os.Create(fileName) if err != nil { fmt.Println(err) return } //循環接收客戶端傳遞的文件內容 for { buf := make([]byte, 2048) n, _ := conn.Read(buf) //結束協程 if string(buf[:n]) == "finish" { fmt.Println(addr + ": 協程結束") runtime.Goexit() } f.Write(buf[:n]) } defer conn.Close() defer f.Close() } func main() { //創建tcp監聽 listen, err := net.Listen("tcp", ":8000") if err != nil { fmt.Println(err) return } defer listen.Close() for { //阻塞等待客戶端 conn, err := listen.Accept() if err != nil { fmt.Println(err) return } //創建協程 go Handler(conn) } }
客戶端實現流程大致如下:
- 提示用戶輸入文件名。接收文件名path(含訪問路徑)
- 使用os.Stat()獲取文件屬性,得到純文件名(去除訪問路徑)
- 主動連接服務器,結束時關閉連接
- 給接收端(服務器)發送文件名conn.Write()
- 讀取接收端回發的確認數據conn.Read()
- 判斷是否為“ok”。如果是,封裝函數SendFile() 發送文件內容。傳參path和conn
- 只讀Open文件, 結束時Close文件
- 循環讀文件,讀到EOF終止文件讀取
- 將讀到的內容原封不動Write給接收端(服務器)
package main import ( "fmt" "io" "net" "os" ) //發送文件到服務端 func SendFile(filePath string, fileSize int64, conn net.Conn) { f, err := os.Open(filePath) if err != nil { fmt.Println(err) return } defer f.Close() var count int64 for { buf := make([]byte, 2048) //讀取文件內容 n, err := f.Read(buf) if err != nil && io.EOF == err { fmt.Println("文件傳輸完成") //告訴服務端結束文件接收 conn.Write([]byte("finish")) return } //發送給服務端 conn.Write(buf[:n]) count += int64(n) sendPercent := float64(count) / float64(fileSize) * 100 value := fmt.Sprintf("%.2f", sendPercent) //打印上傳進度 fmt.Println("文件上傳:" + value + "%") } } func main() { fmt.Print("請輸入文件的完整路徑:") //創建切片,用於存儲輸入的路徑 var str string fmt.Scan(&str) //獲取文件信息 fileInfo, err := os.Stat(str) if err != nil { fmt.Println(err) return } //創建客戶端連接 conn, err := net.Dial("tcp", ":8000") if err != nil { fmt.Println(err) return } defer conn.Close() //文件名稱 fileName := fileInfo.Name() //文件大小 fileSize := fileInfo.Size() //發送文件名稱到服務端 conn.Write([]byte(fileName)) buf := make([]byte, 2048) //讀取服務端內容 n, err := conn.Read(buf) if err != nil { fmt.Println(err) return } revData := string(buf[:n]) if revData == "ok" { //發送文件數據 SendFile(str, fileSize, conn) } }