Golang中goroutine与UDP协议的使用问题求助
Golang中goroutine与UDP协议的使用问题求助 大家好,我想编写一个代码,通过UDP协议从IP地址读取数据,并将接收到的数据和地址写入文本文件。但我找不到它无法工作的原因。有人可以告诉我问题出在哪里以及如何解决吗?
这是我的代码:
package main
import (
"fmt"
"net"
"os"
)
func main() {
file_name := "test.txt"
number_of_data := 100
var buf chan []byte
var addr chan *net.UDPAddr
_, err := os.Create(file_name)
check_eror1(err)
file, err := os.Open(file_name)
check_eror1(err)
for i := 0; i < number_of_data; i++ {
go readudp(addr, buf)
//time.Sleep(3 * time.Second)
v1, ok1 := <-addr
check_eror2(ok1)
v2, ok2 := <-buf
check_eror2(ok2)
_, err := fmt.Fprintln(file, string(i)+string(v1.IP)+string(v1.Port)+string(v2))
fmt.Println(string(i) + string(v1.IP) + string(v1.Port) + string(v2))
check_eror1(err)
fmt.Println("print into the file")
}
file.Close()
}
func readudp(addr chan *net.UDPAddr, buf chan []byte) {
buf1 := make([]byte, 1500)
conn, errlisten := net.ListenUDP("udp", &net.UDPAddr{IP: []byte{0, 0, 0, 0}, Port: 5000, Zone: ""})
check_eror1(errlisten)
n, addr1, erread := conn.ReadFromUDP(buf1)
check_eror1(erread)
fmt.Println("test")
addr <- addr1
buf <- buf1[:n]
close(addr)
close(buf)
}
// write to file
func check_eror1(eror error) {
if eror != nil {
fmt.Println("ERROR")
}
}
func check_eror2(eror bool) {
if eror != true {
fmt.Println("ERROR")
}
}
更多关于Golang中goroutine与UDP协议的使用问题求助的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我怀疑 panic 并不是唯一的输出,我很确定在那之前有一个你通过 fmt.Println 打印的错误信息。
PS:出于某种原因,你的代码中有很多空行,这使得很难将 panic 中的行号映射到你的代码上。第45行是哪一行?
更多关于Golang中goroutine与UDP协议的使用问题求助的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
avishai111:
main.readudp(0x0, 0x0)
这告诉我 main.readudp 的两个参数是 nil。查看你的示例代码,我没有看到 buf 和 addr 被初始化。你能检查一下吗?
请使用代码块,而不是引用块。
同时,请告诉我们你看到的确切错误信息,以及你的程序产生的完整输出。
我现在不在电脑前,而且在孩子们上床睡觉之前(大约3小时内)都不会有电脑可用。
我检查过,它是在名为 “readudp” 的 goroutine 中初始化的,我写了如下代码:
n, addr1, erread := conn.ReadFromUDP(buf1)
if erread != nil {
fmt.Println("eror in read from udp protocol")
}
addr <- addr1
buf <- buf1[:n]
具体是哪里出了问题?与其打印一个通用的、静态的 ERROR,不如打印实际的错误信息,并确保在此处立即停止。
此外,就我个人而言,我不喜欢在辅助函数中进行错误检查。你既无法正确返回错误,也无法正确触发 panic,因为额外的检查调用会混淆堆栈跟踪。
func main() {
fmt.Println("hello world")
}
我可以编译并运行你的程序,它确实创建了文件并在端口5000上进行监听。我可以向该端口发送UDP数据。
没有发生崩溃。
请提供更多信息以及通过网络发送的示例数据。
同时,请使用正确的代码格式。可以直接使用Markdown,或者在文本编辑框中标记你的代码并点击上方的</>按钮。
你说得对,抱歉之前的内容比较混乱,这是整理好的代码。对我来说它会崩溃,我不明白为什么。 这是代码:
func main() {
file_name := "test.txt"
number_of_data := 100
var buf chan []byte
var addr chan *net.UDPAddr
_, err := os.Create(file_name)
if err != nil {
fmt.Println("eror in create file")
}
file, err := os.Open(file_name)
if err != nil {
fmt.Println("eror in open file")
}
for i := 0; i < number_of_data; i++ {
go readudp(addr, buf)
v1, ok1 := <-addr
if ok1 != true {
fmt.Println("error to get the adress to channel v1")
}
v2, ok2 := <-buf
if ok2 != true {
fmt.Println("error to get the data to channel v2")
}
_, err := fmt.Fprintln(file, string(i)+string(v1.IP)+string(v1.Port)+string(v2))
fmt.Println(string(i) + string(v1.IP) + string(v1.Port) + string(v2))
if err != nil {
fmt.Println("eror write to the file")
}
fmt.Println("print into the file")
}
file.Close()
}
func readudp(addr chan *net.UDPAddr, buf chan []byte) {
buf1 := make([]byte, 1500)
conn, errlisten := net.ListenUDP("udp", &net.UDPAddr{IP: []byte{0, 0, 0, 0}, Port: 5000, Zone: ""})
defer conn.Close()
if errlisten != nil {
fmt.Println("eror in listen to adress in udp protocol")
}
n, addr1, erread := conn.ReadFromUDP(buf1)
if erread != nil {
fmt.Println("eror in read from udp protocol")
}
addr <- addr1
buf <- buf1[:n]
}
嗨,我也遇到了这个问题,但是调试控制台输出了错误信息,我不明白这是什么意思:
panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x4bd24e]
goroutine 19 [running]: main.readudp(0x0, 0x0) c:/avishai/opp/main.go:46 +0x10e created by main.main c:/avishai/opp/main.go:23 +0x15b exit status 2 Process exiting with code: 1
这是我写的新代码:
package main import ( "fmt" "net" "os" ) func main() { file_name := "test.txt" number_of_data := 100 var buf chan []byte var addr chan *net.UDPAddr _, err := os.Create(file_name) if err != nil { fmt.Println("eror in create file") } file, err := os.Open(file_name) if err != nil { fmt.Println("eror in open file") } for i := 0; i < number_of_data; i++ { go readudp(addr, buf) //time.Sleep(3 * time.Second) v1, ok1 := <-addr if ok1 != true { fmt.Println("error to get the adress to channel v1") } v2, ok2 := <-buf if ok2 != true { fmt.Println("error to get the data to channel v2") } _, err := fmt.Fprintln(file, string(i)+string(v1.IP)+string(v1.Port)+string(v2)) fmt.Println(string(i) + string(v1.IP) + string(v1.Port) + string(v2)) if err != nil { fmt.Println("eror write to the file") } fmt.Println("print into the file") } file.Close() } func readudp(addr chan *net.UDPAddr, buf chan []byte) { buf1 := make([]byte, 1500) conn, errlisten := net.ListenUDP("udp", &net.UDPAddr{IP: []byte{0, 0, 0, 0}, Port: 5000, Zone: ""}) defer conn.Close() if errlisten != nil { fmt.Println("eror in listen to adress in udp protocol") } n, addr1, erread := conn.ReadFromUDP(buf1) if erread != nil { fmt.Println("eror in read from udp protocol") } //fmt.Println("test") addr <- addr1 buf <- buf1[:n] /* close(addr) close(buf) */ } // write to file /*func check_eror1(eror error) { if eror != nil { fmt.Println("ERROR") } } func check_eror2(eror bool) { if eror != true { fmt.Println("ERROR") } } */
Blockquote
你的代码存在几个关键问题:
- 通道未初始化:
buf和addr通道声明后未使用make初始化 - 通道关闭过早:在
readudp函数中每次调用都关闭通道,导致后续读取失败 - 并发逻辑错误:每次循环都创建新的goroutine和UDP连接
- 文件操作问题:使用
Open打开文件但需要写入权限
以下是修正后的代码:
package main
import (
"fmt"
"net"
"os"
"strconv"
"sync"
)
func main() {
file_name := "test.txt"
number_of_data := 100
// 初始化通道
buf := make(chan []byte, number_of_data)
addr := make(chan *net.UDPAddr, number_of_data)
// 创建并打开文件(使用追加模式)
file, err := os.OpenFile(file_name, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
check_error(err)
defer file.Close()
var wg sync.WaitGroup
// 启动单个UDP接收goroutine
wg.Add(1)
go func() {
defer wg.Done()
readudp(addr, buf)
}()
// 主循环处理接收到的数据
for i := 0; i < number_of_data; i++ {
select {
case v1 := <-addr:
v2 := <-buf
// 正确格式化输出
output := fmt.Sprintf("数据%d: IP=%s, Port=%d, 内容=%s\n",
i, v1.IP.String(), v1.Port, string(v2))
_, err := file.WriteString(output)
check_error(err)
fmt.Print(output)
fmt.Println("已写入文件")
}
}
wg.Wait()
}
func readudp(addr chan *net.UDPAddr, buf chan []byte) {
// 只创建一次UDP连接
conn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 5000,
})
check_error(err)
defer conn.Close()
for {
buf1 := make([]byte, 1500)
n, addr1, err := conn.ReadFromUDP(buf1)
if err != nil {
fmt.Printf("读取错误: %v\n", err)
continue
}
fmt.Println("接收到数据")
addr <- addr1
buf <- buf1[:n]
}
}
func check_error(err error) {
if err != nil {
fmt.Printf("错误: %v\n", err)
}
}
或者使用更简洁的单goroutine版本:
package main
import (
"fmt"
"net"
"os"
)
func main() {
file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Printf("文件错误: %v\n", err)
return
}
defer file.Close()
conn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.IPv4(0, 0, 0, 0),
Port: 5000,
})
if err != nil {
fmt.Printf("UDP错误: %v\n", err)
return
}
defer conn.Close()
for i := 0; i < 100; i++ {
buf := make([]byte, 1500)
n, addr, err := conn.ReadFromUDP(buf)
if err != nil {
fmt.Printf("读取错误: %v\n", err)
continue
}
output := fmt.Sprintf("数据%d: IP=%s, Port=%d, 内容=%s\n",
i, addr.IP.String(), addr.Port, string(buf[:n]))
_, err = file.WriteString(output)
if err != nil {
fmt.Printf("写入错误: %v\n", err)
}
fmt.Print(output)
fmt.Println("已写入文件")
}
}
主要修改:
- 使用
make初始化通道 - 将UDP连接创建移到循环外部
- 使用
OpenFile替代Create+Open - 修正字符串格式化方式
- 移除过早的通道关闭操作


