golang udp连接每隔一次写入就被拒绝

I ran this UDP client program on ubuntu linux 16.04:

package main

import (
    "fmt"
    "net"
    "time"
    "strconv"
)

func CheckError(err error) {
    if err  != nil {
        fmt.Println("Error: " , err)
    }
}

func main() {
    ServerAddr,err := net.ResolveUDPAddr("udp","127.0.0.1:10001")
    CheckError(err)

    LocalAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
    CheckError(err)

    Conn, err := net.DialUDP("udp", LocalAddr, ServerAddr)
    CheckError(err)

    defer Conn.Close()
    i := 0
    for {
        msg := strconv.Itoa(i)
        i++
        buf := []byte(msg)
        _,err := Conn.Write(buf)
        if err != nil {
            fmt.Println(msg, err)
        }
        time.Sleep(time.Second * 1)
    }
}

It produces this output:

$ go run server.go 
1 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused
3 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused
5 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused

But I expected this output instead:

$ go run server.go 
1 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused
2 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused
3 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused
4 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused
5 write udp 127.0.0.1:58703->127.0.0.1:10001: write: connection refused

tcpdump says:

15:28:46.453313 IP localhost.47993 > localhost.10001: UDP, length 1
15:28:46.453338 IP localhost > localhost: ICMP localhost udp port 10001 unreachable, length 37
15:28:48.453821 IP localhost.47993 > localhost.10001: UDP, length 1
15:28:48.453852 IP localhost > localhost: ICMP localhost udp port 10001 unreachable, length 37
15:28:50.454242 IP localhost.47993 > localhost.10001: UDP, length 1
15:28:50.454271 IP localhost > localhost: ICMP localhost udp port 10001 unreachable, length 37

Why does this happen every other time conn.Write writes instead of every time? I'm not blaming go, I just want to learn why.

dongpu8935
dongpu8935 使用ListenUDP创建套接字。
接近 3 年之前 回复
dua6992
dua6992 我宁愿使用未连接的UDP套接字。PacketConnAPI会这样做吗?
接近 3 年之前 回复
dongxinyue2817
dongxinyue2817 “连接的UDP套接字”具有默认的目标地址。来自Linuxudpdocs在套接字上调用connect(2)时,将设置默认目标地址,并且现在可以使用send(2)或write(2)发送数据报,而无需指定目标地址。主要是为了方便,但还有其他区别。例如调用recv将仅从连接的地址接收数据包,并且ICMP条件如您在此处看到的。
接近 3 年之前 回复
douzhong1730
douzhong1730 我以为UDP无连接是什么“连接的UDP套接字”?他们通常建议在哪里避免这种情况?
接近 3 年之前 回复
duanbairan4235
duanbairan4235 除非您有一个要求,否则通常建议避免使用连接的UDP套接字。
接近 3 年之前 回复
dongliantong3229
dongliantong3229 您可以分享服务器如何处理连接吗?好像被挡住了或类似的东西
接近 3 年之前 回复

2个回答



如果您仔细观察数据包捕获,您会发现它正在</ em>答复每个数据包 且无法访问ICMP,并且您仅每隔一个数据包发送</ em>。 如果检查 Write </ code>中的返回值,您还将看到没有数据写入其他所有数据包。 </ p>

因为UDP没有真正的连接,并且对于任何发送的数据包都没有ACK,所以“连接”的UDP套接字模拟发送失败的最佳方法是保存ICMP响应,并且 在下一次写入时将其作为错误返回。 </ p>

因此,发送第一个数据包,接收到ICMP不可达消息,第二个发送操作失败并返回错误,因此没有数据包被发送,并且循环重复。</ p>

</ div>

展开原文

原文

If you look more closely at the packet capture, you'll notice that it is replying to every packet with an ICMP unreachable, and you are only sending every other packet. If you inspect the return value from Write, you'll also see that no data was written on every other packet.

Because UDP has no real connection and there is no ACK for any packets sent, the best a "connected" UDP socket can do to simulate a send failure is to save the ICMP response, and return it as an error on the next write.

So the first packet is sent, an ICMP unreachable message is received, the second send operation fails and returns the error, so no packet is sent, and the cycle repeats.

Try

LocalAddr, err := net.ResolveUDPAddr("udp", ":0")

or

LocalAddr, err := net.ResolveUDPAddr("udp", "<ip address of outgoing interface>:0")

This should work

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问