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)
    }
}
复制代码

 

如果你感觉有收获,欢迎给我打赏 ———— 以激励我输出更多优质内容,联系QQ:2575404985
        
posted @   样子2018  阅读(3112)  评论(1编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示