【问题标题】:How to send broadcast on a specific UDP port? (Getting error: `sendto failed: EINVAL`)如何在特定的 UDP 端口上发送广播? (收到错误:`sendto failed: EINVAL`)
【发布时间】:2017-09-08 19:32:24
【问题描述】:

免责声明:我知道已经有相同主题的问题,但下面的问题与其他问题不同。

我正在尝试在某个端口上广播数据包。

这不起作用。我的代码:(我在我的实际手机上运行它)

//Creating the socket (It's a class field, not a private element)
bcSock = new DatagramSocket(DEVICE_PORT, bcAddress);//bcAddress is explained below
bcSock.setBroadcast(true);
bcSock.setSoTimeout(LISTEN_TIMEOUT);
//Somewhere else in the code, creating the packet/sending it
 byte[] buf = PACKET_CONTENT.getBytes();
    DatagramPacket dp = new DatagramPacket(buf, buf.length, bcAddress, PORT);
    new SendUDPTask() {
        @Override
        public void handleException(Exception e) {
            //TODO Handle
            e.printStackTrace();
        }
    }.execute(bcSock, dp, LISTEN_TIMEOUT);

SendUDPTask 是一个公共类,它只是这样做:sock.send(dp);。

bcAddress是使用此方法生成的默认广播IP:

public static InetAddress getBroadcastAddress(Activity activity) throws IOException {
    WifiManager wifi = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
    DhcpInfo dhcp = wifi.getDhcpInfo();
    // handle null somehow

    int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
    byte[] quads = new byte[4];
    for (int k = 0; k < 4; k++)
        quads[k] = (byte) (broadcast >> (k * 8));
    return InetAddress.getByAddress(quads);
}

这样我得到这个错误:

java.net.SocketException: sendto failed: EINVAL (Invalid argument)
    at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:542)
    at libcore.io.IoBridge.sendto(IoBridge.java:511)
    at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:184)
    at java.net.DatagramSocket.send(DatagramSocket.java:305)
    at me.nonamesldev.smarthouse.SendUDPTask.doInBackground(SendUDPTask.java:27)
    at me.nonamesldev.smarthouse.SendUDPTask.doInBackground(SendUDPTask.java:17)

(第 27 行是 socket.send(packet) 部分。)

尝试像DatagramSocket s = new DatagramSocket(8888); 这样创建套接字也不起作用,并且在DatagramSocket.send 上抛出一个NullPointerException - null buffer || null address,即使文档说这应该没问题:

DatagramSocket s = new DatagramSocket(null); s.bind(new InetSocketAddress(8888)); 相当于:DatagramSocket s = new DatagramSocket(8888); 这两种情况都会创建一个 DatagramSocket 能够在 UDP 端口 8888 上接收广播。

我该怎么办?我只想在 Android 的某个端口上通过 UDP 广播。为什么要这么难?

提前致谢!

编辑:我也尝试过以这种方式创建套接字:

DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
bcSock.bind(new InetSocketAddress(bcAddress, PORT));

而不是bcSock = new DatagramSocket(DEVICE_PORT, bcAddress);,会产生同样的错误。

【问题讨论】:

  • 你要删除多少次并重新提出这个问题?
  • @EJP 现在这是一个不同的问题,我的最后一个问题也被错误地关闭并标记为不相关问题的重复。所以,这是第二次了。请删除您的评论。

标签: java android sockets networking broadcast


【解决方案1】:

这对我有用:

发件人

bcSock = new DatagramSocket();
bcSock.setBroadcast(true);
byte[] buf = PACKET_CONTENT.getBytes();
DatagramPacket dp = new DatagramPacket(buf, buf.length, bcAddress, PORT);
bcSock.send(dp);

接收器

DatagramSocket ds = new DatagramSocket(PORT);
byte[] buf = new byte[PACKET_CONTENT.getBytes().length];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);

【讨论】:

  • 非常感谢!套接字中没有地址、设置广播标志和将bcAddress 放入数据包中的组合是我没有想到的:)
【解决方案2】:

您不应尝试将套接字绑定到广播地址。使用 INADDR_ANY,它在 Java 中是 InetAddress 的 null。

【讨论】:

  • 使用 null InetAddress 会产生以下异常:NullPointerException: Destination address is null。
  • 在DatagramPacket 中使用空的InetAddress 可以做到这一点。我没有提到任何这样的事情。我说的是socket。请阅读这里写的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-03
  • 1970-01-01
  • 2020-02-21
  • 2018-02-27
  • 1970-01-01
  • 2018-05-29
相关资源
最近更新 更多