Go语言 之TCP文件传输
服务端实现流程大致如下:
- 创建监听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) } }
如果你感觉有收获,欢迎给我打赏 ———— 以激励我输出更多优质内容,联系QQ:2575404985
.png)

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· 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