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

10 回复

我怀疑 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。查看你的示例代码,我没有看到 bufaddr 被初始化。你能检查一下吗?

请使用代码块,而不是引用块。

同时,请告诉我们你看到的确切错误信息,以及你的程序产生的完整输出。

我现在不在电脑前,而且在孩子们上床睡觉之前(大约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]
}

我的程序创建了一个文件,但它仍然是空的。我还使用Packet Sender通过UDP协议向我代码中写入的地址发送数据。当我在VS Code平台上运行代码时,在调试控制台中看到的错误是:

panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x4bd2b4]

goroutine 19 [running]: main.readudp(0x0, 0x0) c:/Users/lab3/Desktop/go_test/main.go:45 +0x114 created by main.main c:/Users/lab3/Desktop/go_test/main.go:23 +0x15b exit status 2 Process exiting with code: 1

这是代码:

func main() {

        fileName := "test.txt"

        numberOfData := 2

        var buf chan []byte

        var addr chan *net.UDPAddr

        _, err := os.Create(fileName) // create file

        if err != nil {

            fmt.Println("eror in create file")

        }

        file, err := os.Open(fileName) // open file

        if err != nil {

            fmt.Println("eror in open file")

        }

        for i := 0; i < numberOfData; i++ { // create go routine

            go readudp(addr, buf) //and write the data that recive from go rouitne to  thefile

            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) { // goroutine that listen to udp and read from udp

        buf1 := make([]byte, 1500)

        conn, errlisten := net.ListenUDP("udp", &net.UDPAddr{IP: []byte{127, 0, 0, 1}, 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

你的代码存在几个关键问题:

  1. 通道未初始化bufaddr通道声明后未使用make初始化
  2. 通道关闭过早:在readudp函数中每次调用都关闭通道,导致后续读取失败
  3. 并发逻辑错误:每次循环都创建新的goroutine和UDP连接
  4. 文件操作问题:使用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("已写入文件")
    }
}

主要修改:

  1. 使用make初始化通道
  2. 将UDP连接创建移到循环外部
  3. 使用OpenFile替代Create+Open
  4. 修正字符串格式化方式
  5. 移除过早的通道关闭操作
回到顶部