Go語言 之TCP文件傳輸


服務端實現流程大致如下:

  1. 創建監聽listener,程序結束時關閉。
  2. 阻塞等待客戶端連接,程序結束時關閉conn。
  3. 讀取客戶端發送文件名。保存fileName。
  4. 回發“ok”給客戶端做應答
  5. 封裝函數 RecvFile接收客戶端發送的文件內容。傳參fileName 和conn
  6. 按文件名Create文件,結束時Close
  7. 循環Read客戶端發送的文件內容,當讀到EOF說明文件讀取完畢。
  8. 將讀到的內容原封不動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)
    }
}

客戶端實現流程大致如下:

  1. 提示用戶輸入文件名。接收文件名path(含訪問路徑)
  2. 使用os.Stat()獲取文件屬性,得到純文件名(去除訪問路徑)
  3. 主動連接服務器,結束時關閉連接
  4. 給接收端(服務器)發送文件名conn.Write()
  5. 讀取接收端回發的確認數據conn.Read()
  6. 判斷是否為“ok”。如果是,封裝函數SendFile() 發送文件內容。傳參path和conn
  7. 只讀Open文件, 結束時Close文件
  8. 循環讀文件,讀到EOF終止文件讀取
  9. 將讀到的內容原封不動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)
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM