一、传输整体流程发送端 (客户端) ↔ 接收端 (服务端) 自定义简易传输协议客户端先发送文件名服务端收到文件名回复ok客户端收到 ok 后分片读取本地文件发送二进制文件内容服务端循环接收二进制数据写入新文件传输完成二、核心前置 API 说明os.Stat(path)获取文件元信息可拿到文件名、文件大小校验文件是否存在os.Open()只读打开本地文件发送端使用os.Create()创建新文件接收端使用file.Read(buf)读取文件到缓冲区返回实际读取字节数读到文件末尾返回io.EOFconn.Read/conn.WriteTCP 连接读写网络数据传输缓冲区分片传输使用 4KB 缓冲避免一次性加载大文件造成内存溢出三、客户端发送代码 send.gogopackage main import ( fmt io net os ) func main() { // 输入待传输文件路径 var path string fmt.Println(请输入需要传输的文件路径) fmt.Scan(path) // 获取文件信息校验文件是否存在 info, err : os.Stat(path) if err ! nil { fmt.Println(os.Stat err , err) return } // 主动连接文件服务端 conn, err1 : net.Dial(tcp, 127.0.0.1:8000) if err1 ! nil { fmt.Println(net.Dial err1 , err1) return } defer conn.Close() // 第一步发送文件名给服务端 _, err : conn.Write([]byte(info.Name())) if err ! nil { fmt.Println(发送文件名 err , err) return } // 等待服务端ok回复 buf : make([]byte, 1024) n, err1 : conn.Read(buf) if err1 ! nil { fmt.Println(读取服务端响应 err1 , err1) return } if string(buf[:n]) ! ok { fmt.Println(服务端未就绪终止传输) return } // 打开本地待发送文件 f, err : os.Open(path) if err ! nil { fmt.Println(打开文件失败 err , err) return } defer f.Close() // 4KB缓冲区循环分片发送文件内容 sendBuf : make([]byte, 1024*4) for { readNum, err : f.Read(sendBuf) if err ! nil { if err io.EOF { fmt.Println(文件发送完毕) } else { fmt.Println(读取文件 err , err) } break } // 发送本次读到的有效数据 _, err conn.Write(sendBuf[:readNum]) if err ! nil { fmt.Println(发送文件数据失败 err , err) return } } }四、服务端接收代码 recv.gogopackage main import ( fmt io net os ) func main() { // 监听tcp端口 listener, err : net.Listen(tcp, 127.0.0.1:8000) if err ! nil { fmt.Println(net.Listen err , err) return } defer listener.Close() fmt.Println(文件接收服务启动监听8000端口) // 阻塞等待客户端连接 conn, err1 : listener.Accept() if err1 ! nil { fmt.Println(listener.Accept err , err1) return } defer conn.Close() fmt.Println(客户端已连接) // 先读取客户端发送的文件名 buf : make([]byte, 1024) n, err : conn.Read(buf) if err ! nil { fmt.Println(读取文件名 err , err) return } fileName : string(buf[:n]) fmt.Println(待接收文件名称, fileName) // 向客户端回复ok表示准备接收文件内容 _, err conn.Write([]byte(ok)) if err ! nil { fmt.Println(发送ok响应失败 err , err) return } // 调用函数接收完整文件 RecvFile(fileName, conn) } // RecvFile 根据文件名创建文件循环接收网络数据写入本地 func RecvFile(fileName string, conn net.Conn) { f, err : os.Create(fileName) if err ! nil { fmt.Println(os.Create 创建文件 err , err) return } defer f.Close() recvBuf : make([]byte, 1024*4) for { readNum, err : conn.Read(recvBuf) if err ! nil { if err io.EOF { fmt.Println(文件接收完毕) } else { fmt.Println(conn.Read 读取文件数据 err , err) } break } if readNum 0 { fmt.Println(文件传输结束) break } // 将读到的有效数据写入本地文件 _, err f.Write(recvBuf[:readNum]) if err ! nil { fmt.Println(写入文件失败 err , err) return } } }五、运行测试步骤先运行接收端 recv.go启动监听服务新开终端运行发送端 send.go输入本地文件路径图片、txt、压缩包均可传输完成后服务端同级目录生成同名文件六、重点复习 踩坑总结必须分片读写文件大文件一次性读取会造成内存溢出统一使用 4KB 缓冲读写缓冲区时必须截取有效长度buf[:n]否则缓冲区残留脏数据文件损坏传输流程不能颠倒先发文件名→回 ok→传文件内容自定义协议避免粘包问题io.EOF是文件正常读取结束标识其他 error 属于异常文件、TCP 连接必须搭配defer Close()避免文件句柄、网络资源泄漏仅支持单客户端单次文件传输拓展可使用 goroutine 实现并发多客户端上传