【问题标题】:UDP-Client written in Golang fails to receive Message from Server用 Golang 编写的 UDP-Client 无法接收来自服务器的消息
【发布时间】:2016-03-04 13:16:52
【问题描述】:

我编写了一个 Java 客户端,它向广播地址发送消息。

我还写了一个Java Server,它接受所有发送的消息并将消息发送回客户端。

现在我想尝试在 Go 中做同样的事情,只是为了获得一些经验。服务器工作正常,正在接收消息并响应 Java 客户端。

但我的 Go 客户端仅向 Go/Java 服务器发送消息,但没有收到任何返回的消息。根据wireshark,消息被发送回正确的IP和端口,但显然端口无法访问。

我的代码如下: 转到服务器:

package main

import (
    "fmt"
    "log"
    "net"
)

func main() {
    //Resolving address
    udpAddr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:8888")

    if err != nil {
        log.Println("Error: ", err)
    }

    // Build listining connections
    conn, err := net.ListenUDP("udp", udpAddr)

    defer conn.Close()

    if err != nil {
        log.Println("Error: ", err)
    }

    // Interacting with one client at a time
    for {
        fmt.Println(">>>Ready to receive broadcast packets!")

        // Receiving a message
        recvBuff := make([]byte, 15000)
        _, rmAddr, err := conn.ReadFromUDP(recvBuff)

        if err != nil {
            panic(err)
        }

        fmt.Println(">>>Discovery packet received from: " + rmAddr.String())
        fmt.Println(">>>Packet received; data: " + string(recvBuff))

        // Sending the same message back to current client
        conn.WriteToUDP(recvBuff, rmAddr)

        fmt.Println(">>>Sent packet to: " + rmAddr.String())

} }

去客户端:

package main

import (
    "fmt"
    "log"
    "net"
    "os"
)

func main() {
    service := "158.129.239.255:8888"

    // Resolving Address
    RemoteAddr, err := net.ResolveUDPAddr("udp", service)

    // Make a connection
    conn, err := net.DialUDP("udp", nil, RemoteAddr)

    defer conn.Close()

    // Exit if some error occured
    if err != nil {
        log.Fatal(err)
        os.Exit(1)
    }

    // write a message to server
    message := []byte("message")

    _, err = conn.Write(message)
    fmt.Println(">>> Request packet sent to: 158.129.239.255 (DEFAULT)")

    if err != nil {
        log.Println(err)
    }

    // Receive response from server
    buf := make([]byte, 15000)
    amountByte, remAddr, err := conn.ReadFromUDP(buf)

    if err != nil {
        log.Println(err)
    } else {
        fmt.Println(amountByte, "bytes received from", remAddr)
    }

}

Java 客户端:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BroadcastUDPClient {

    public static void main(String[] args) {
        // Find the server using UDP broadcast
        try {
            //Open a random port to send the package
            DatagramSocket sendSD = new DatagramSocket();
            sendSD.setBroadcast(true);

                byte[] sendData = "message".getBytes();

            //Try the 255.255.255.255 first
            try {
                DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("158.129.239.255"), 8888);
                sendSD.send(sendPacket);
                System.out.println(">>> Request packet sent to: 158.129.239.255 (DEFAULT)");
            } catch (Exception e) {
            }

            //Wait for a response
            byte[] recvBuf = new byte[15000];
            DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length);
            sendSD.receive(receivePacket);

            //We have a response
            System.out.println(">>> Broadcast response from server: " + receivePacket.getAddress().getHostAddress());
            String message = new String(receivePacket.getData()).trim();
            System.out.println(">>> Message Body: " + message);

            //Close the port!
            sendSD.close();
        } catch (IOException ex) {
            Logger.getLogger(BroadcastUDPClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

我的 Go 客户端做错了什么?

【问题讨论】:

  • 不要忽略从 WriteToUDP 得到的错误
  • 另外:您不处理其他几个错误。并且 log.Fatal 无论如何都会结束程序,永远不会到达 os.Exit。

标签: go udp broadcast


【解决方案1】:

即使您只想从连接发送 UDP 数据包,您通常也希望使用 ListenUDP 创建连接,并使用 ReadFromUDPWriteToUDP 方法。

当您使用DialUDP 时,它会创建一个“已连接”的 UDP 套接字,带有一个隐式远程端点,它将过滤传入的数据包。来自 Linux connect 手册页:

如果套接字 sockfd 是 SOCK_DGRAM 类型,那么 addr 是默认发送数据报的地址,也是接收数据报的唯一地址。

【讨论】:

  • 谢谢!有意义的是,我只会从“已连接”连接中获取消息。但话又说回来,为什么 Go 会建立连接? UDP不是无连接的吗?
  • @MarvinAhlgrimm:是也不是;)。 Go 仅公开底层 berkeley 套接字 API 中可用的内容。 DialUDP 使用 connect 系统调用,因此您可以从单个主机发送和接收,这是该标准 API 的一部分。 UDP 仍然是“无连接”的,但这提供了方便,在与单个主机通信时只需要调用recvsend,而不必过滤掉杂散数据包。
  • 这是一个巨大的帮助。为什么 ReadFrom 在DialUDP 上不起作用肯定不直观。尤其是考虑到几乎每个 UDP 示例都使用 Dial over Listen。
  • DNS 是这样工作的吗?如果属实,我想知道 DNS 服务器如何“响应”他们(发件人)在专用网络中的发件人。
【解决方案2】:

如果你不忽略从 WriteToUDP 返回的错误,它实际上会给你一个错误:“sendto: message to long”

在 OSX 上,最大 UDP 数据报大小默认设置为 9216 字节。您尝试发送 15000 个字节。

如果您只想写回收到的内容,请写下

recvBuff[:n]

,其中 n 是之前接收到的字节数。

【讨论】:

  • 您好,感谢您对此进行调查。我刚刚从 WriteToUDP 的结果中分配了 amountBits,错误。 amountBits 设置为 7 并且 err 显然为零。我还将字节数减少到合理的数量(256),但是根据wireshark仍然无法访问Go客户端的端口
  • 对我来说它在之后有效。您使用的是什么机器/操作系统和 Go 版本?有防火墙吗?尝试只在 localhost:8888 上收听。
  • 另外:amountBytes 不会改变你的 recvBuff 的长度。另外你不应该把它命名为amountBytes,只是n。
猜你喜欢
  • 2017-04-05
  • 2023-03-31
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-06
相关资源
最近更新 更多