Golang UDP文件传输遇端口占用错误及代码问题求助
问题分析与解决方案
一、端口占用错误的核心原因
你的端口占用错误完全来自接收端代码的逻辑缺陷:
take_file函数外层是无限for循环,每次循环都会调用ListenUDP绑定同一个端口0.0.0.0:12345,但defer connection.Close()要等到整个函数结束才会执行,第一次绑定的连接永远不会被释放,后续循环再次绑定同一端口时必然触发“地址已被占用”的错误。- UDP是无连接协议,监听端口只需要初始化一次,不需要反复创建监听连接。
二、全代码逻辑错误修复
1. 接收函数take_file修复
将UDP监听移到外层循环之外,只初始化一次连接:
func take_file() { udp_address, address_error := net.ResolveUDPAddr("udp", "0.0.0.0:"+port) if address_error != nil { fmt.Println(address_error.Error()) os.Exit(1) } // 仅创建一次UDP监听,避免重复绑定端口 connection, connection_error := net.ListenUDP("udp", udp_address) if connection_error != nil { fmt.Println(connection_error.Error()) os.Exit(1) } defer connection.Close() // 函数退出时统一关闭连接 for { datas := make([]byte, buffer) n, _, reading_error := connection.ReadFromUDP(datas) if reading_error != nil { fmt.Println(reading_error.Error()) os.Exit(1) } if string(datas[:n]) == EOF { fmt.Println("文件接收完成") continue } fmt.Println(string(datas[:n])) } }
2. 发送函数send_file修复
移除不必要的内层循环,同时避免defer导致的连接无法及时释放:
func send_file(file_path, receiver_ip string) { udp_address, address_error := net.ResolveUDPAddr("udp", receiver_ip+":"+port) if address_error != nil { fmt.Println(address_error.Error()) os.Exit(1) } for { connection, connection_error := net.DialUDP("udp", nil, udp_address) if connection_error != nil { fmt.Println(connection_error.Error()) time.Sleep(time.Second) // 出错后延迟重试,避免频繁打印日志 continue } // 提取文件名 file_name := file_name_extracter(file_path) _, writing_error := connection.Write([]byte(file_name)) if writing_error != nil { fmt.Println(writing_error.Error()) connection.Close() continue } // 分块发送文件,新增错误处理 if err := read_file_and_send(file_path, connection); err != nil { fmt.Println(err.Error()) connection.Close() continue } _, writing_error = connection.Write([]byte(EOF)) if writing_error != nil { fmt.Println(writing_error.Error()) connection.Close() continue } fmt.Println("文件发送完成") connection.Close() // 每次发送完成后手动关闭连接 // 如果不需要无限重复发送,此处可添加break // break } }
3. 分块读取函数read_file_and_send修复
修复变量冲突、分块逻辑错误,优化文件读取效率:
// 修改函数返回错误,方便上层统一处理 func read_file_and_send(file_path string, connection net.UDPConn) error { file, opening_error := os.Open(file_path) if opening_error != nil { return opening_error } defer file.Close() // 使用全局buffer定义固定大小的缓冲区,避免变量名冲突 buf := make([]byte, buffer) for { n, reading_error := file.Read(buf) if reading_error != nil { if reading_error == io.EOF { break // 文件读取完成 } return reading_error } // 仅发送实际读取到的字节,避免冗余空字节 if _, err := connection.Write(buf[:n]); err != nil { return err } } return nil }
三、额外提示
- UDP是无连接、不可靠协议,当前代码没有处理丢包、乱序问题,实际传输大文件大概率会出现数据损坏,建议添加序列号、确认应答机制,或直接改用TCP协议实现可靠传输。
- 如果修改代码后仍出现端口占用,可通过系统命令排查:Windows用
netstat -ano | findstr :12345,Linux/macOS用lsof -i :12345,找到占用进程后关闭即可。
内容的提问来源于stack exchange,提问作者shiva13
相关产品推荐
相关产品推荐

