• 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)
        }
    }
  • 相关阅读:
    CREATE VIEW
    CREATE USER
    安全层次
    PHP json_decode 函数解析 json 结果为 NULL 的解决方法
    Java实现 LeetCode 7整数反转
    Java实现 LeetCode 6 Z字形变换
    Java实现 LeetCode 6 Z字形变换
    Java实现 LeetCode 6 Z字形变换
    Java实现 LeetCode 5 最长回文子串
    Java实现 LeetCode 5 最长回文子串
  • 原文地址:https://www.cnblogs.com/yang-2018/p/11147418.html
Copyright © 2020-2023  润新知