是golang net.UDPConn和net.TCPConn线程安全?我可以在多线程中读取或写入单个UDPConn对象吗?

时间:2015-02-18 04:03:24

标签: sockets go thread-safety

1.我们可以在同一个net.UDPConn或net.TCPConn对象上调用一个线程的发送和另一个线程的recv吗?

2.我们可以从同一网络上的不同线程并行调用多个发送.UDPConn或net.TCPConn对象吗?

我也找不到同样好的文档。 golang socket api是否安全?

我发现很难测试它是否是线程安全的。 任何指示方向都会有所帮助。

我的测试代码如下:

package main

import (
    "fmt"
    "net"
    "sync"
)

func udp_server() {
    // create listen
    conn, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 8080,
    })
    if err != nil {
        fmt.Println("listen fail", err)
        return
    }
    defer conn.Close()

    var wg sync.WaitGroup
    for i := 0; i < 10; i = i + 1 {
        wg.Add(1)
        go func(socket *net.UDPConn) {
            defer wg.Done()
            for {
                // read data
                data := make([]byte, 4096)
                read, remoteAddr, err := socket.ReadFromUDP(data)
                if err != nil {
                    fmt.Println("read data fail!", err)
                    continue
                }
                fmt.Println(read, remoteAddr)
                fmt.Printf("%s\n\n", data)

                // send data
                senddata := []byte("hello client!")
                _, err = socket.WriteToUDP(senddata, remoteAddr)
                if err != nil {
                    return
                    fmt.Println("send data fail!", err)
                }
            }
        }(conn)
    }
    wg.Wait()
}

func main() {
    udp_server()
}

这个测试代码可以吗?

2 个答案:

答案 0 :(得分:12)

net.Conn的文档说:

  

多个goroutine可以同时调用Conn上的方法。

答案 1 :(得分:2)

  

多个goroutine可以同时调用Conn上的方法。

我对上述文档的解释是,如果您从多个go例程调用ReadWritenet.Conn,并且调用Write,则不会发生任何灾难性事件来自多个go例程的net.Conn将被序列化,以便来自2个单独调用Write的字节在写入网络时不会交错。

您提供的代码存在的问题是,无法保证Write将一次性写入提供给它的整个字节切片。您忽略了已写入的字节数的指示。

_, err = socket.WriteToUDP(senddata, remoteAddr)

所以为了确保你写下你需要循环的所有内容并调用Write直到发送了所有senddata。但net.Conn仅确保来自调用Write的数据不会交错。鉴于您可能会发送一个包含多个写入调用的数据块,因此无法保证单个数据块能够完整地到达目标。

所以例如3&#34;你好客户!&#34;消息可以以下列形式到达。

&#34; hellohellohello客户!客户! !客户&#34;

因此,如果您希望在多个go例程的net.Conn上编写可靠的消息,则需要同步这些例程以确保单个消息的完整写入。

如果我想这样做,作为第一次尝试,我将从一个或多个消息通道读取一个例行程序并写入net.Conn,然后多个go例程可以写入这些消息通道。 / p>