【问题标题】:Listening datagram socket with any ip and any port number android使用任何 ip 和任何端口号 android 侦听数据报套接字
【发布时间】:2016-10-18 16:08:10
【问题描述】:

您好,我正在使用具有特定端口号的 DatagramSocket 发送广播。它成功发送消息。但是,当我监听带有开放 IP 地址和任何端口号的接收消息时,它会抛出 sockettimeoutexception。但是我连接到同一个网络。

//清单

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

//全局定义端口号

int PORT=2739;

// 启动异步任务

new MyClientTask().execute();

///异步任务

public class MyClientTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... arg0) {

            new PacketSender().run();
            new PacketReceiver().run();

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);


        }

    }

这是我的发送请求

public class PacketSender implements Runnable {
        @Override
        public void run() {
            DatagramSocket sendSoc = null;
            try {
                sendSoc = new DatagramSocket();
                sendSoc.setBroadcast(true);
                sendSoc.setSoTimeout(5000);
                sendSoc.setReuseAddress(true);
                byte[] ip = prop.ToBuffer();
                DatagramPacket packet = new DatagramPacket(ip,
                        ip.length, getBroadcastIp(), PORT);
                Log.d("Sending", packet.getAddress().getHostAddress() + " " + packet.getPort());
                sendSoc.send(packet);
                sendSoc.close();
            } catch (IOException e) {
                Log.d("Send", "IOException");
                e.printStackTrace();
                if (sendSoc != null)
                    sendSoc.close();
            }
        }
    }

这是我的收听请求

public class PacketReceiver implements Runnable {
        @Override
        public void run() {
            DatagramSocket receiveSoc = null;
            try {
              //here 0 represent any port number including system reserved port number
                receiveSoc = new DatagramSocket(0, InetAddress.getByName("0.0.0.0"));  
                receiveSoc.setBroadcast(false); //also tried with true
                receiveSoc.setSoTimeout(5000);  //alse tried with removing timeout value

                int i = 0;
                while (true) {
                    Log.d("data value", " " + i);
                    i++;
                    byte buf[] = new byte[1024];
                    DatagramPacket pack = new DatagramPacket(buf, buf.length);

                    try {
                        receiveSoc.receive(pack);

                        String message = new String(pack.getData()).trim();
                        Log.i("test", message + " server ip : " + pack.getAddress().getHostAddress());

                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                }
            } catch (SocketTimeoutException e) {
                Log.d("Main", "SocketTimeoutException");
                e.printStackTrace();
                receiveSoc.close();
                new PacketReceiver().run();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                Log.d("Response", "IOException");
                e.printStackTrace();
            }
        }
    }

//获取广播ip

public InetAddress getBroadcastIp() throws IOException {
        DhcpInfo dhcp = myWifiManager.getDhcpInfo();
        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) & 0xFF);
        return InetAddress.getByAddress(quads);
    }

它可以接收来自局域网中所有主机的广播消息,除了我想要通信的硬件。我可以向它发送广播。但我无法从这个特定设备接收广播。

【问题讨论】:

  • 如果不清楚请评论我。

标签: android sockets broadcast datagram socket-timeout-exception


【解决方案1】:

我从下面解决了这个问题。网络中的数据包转发没有问题。我在 setBroadcast 值为 true 的同一个套接字对象上发送和接收广播。所以套接字发送广播并监听来自同一广播的任何广播。您不应该使用不同的套接字对象来监听广播。我很晚才明白。

public class PacketSender extends Thread {
        @Override
        public void run() {
            DatagramSocket sendSoc = null;
            try {
                sendSoc = new DatagramSocket();
                sendSoc.setBroadcast(true);
                InetSocketAddress  address = new InetSocketAddress(getBroadcastQuadIp(), PORT);

                byte[] ip = prop.ToBuffer();
                DatagramPacket packet = new DatagramPacket(ip,
                        ip.length, address.getAddress(), address.getPort());


                sendSoc.send(packet);    

                //////////// receiver begin
                int i = 0;
                while (true) {

                    i++;

                    final byte buf[] = new byte[1024];
                    final DatagramPacket pack = new DatagramPacket(buf, buf.length);
                    try {
                        sendSoc.receive(pack);

                        String message = new String(pack.getData()).trim();

                        Log.i("test", message + " server ip : " + pack.getAddress().getHostAddress());

                    } catch (UnknownHostException e) {
                        e.printStackTrace();

                    }
                }
            } catch (IOException e) {
                Log.d("Send", "IOException");
                e.printStackTrace();
                if (sendSoc != null)
                    sendSoc.close();
            }
        }
    }

【讨论】:

    【解决方案2】:

    对您的代码进行以下更改:

    public class PacketSender implements Runnable {
    
        @Override
        public void run() {
    
            // ...
    
            DatagramPacket packet = new DatagramPacket(ip,
                    ip.length, InetAddress.getByName("255.255.255.255"), PORT);
    
            // ...
        }
    }
    
    public class PacketReceiver implements Runnable {
    
        @Override
        public void run() {
    
            // ...
    
            receiveSoc = new DatagramSocket(PORT, InetAddress.getByName("0.0.0.0"));
    
            // ...
        }
    }
    

    更新

    MyClientTask 代码不起作用,因为它依次调用发送方和接收方。发送者不会发送给任何人,接收者将永远等待没有消息。您必须在接收方已经在监听数据报时呼叫发送方。

    所以,而不是

    new MyClientTask().execute();
    

    你会想要类似的东西

    new Thread(new PacketReceiver()).start();
    
    // Just to make sure that the receiver has started up.
    // You'll want to do a different kind of synchronization.
    SystemClock.sleep(50);
    
    new Thread(new PacketSender()).start();
    

    【讨论】:

    • 感谢您的回复。它不工作。即使它不发送味精。之前还好。
    • 谢谢它不工作我已经这样做了,所以我简化了它。它可以接收来自 LAN 中所有主机的广播消息,除了我想要通信的硬件。我可以向它发送广播。但我无法从这个特定设备接收广播。在局域网中,我的 ip 是 192.168.0.100,正在监听的设备 ip 是 192.168.0.101。除了这个 ip,我可以在 LAN 中接收所有广播消息。但这不是我的需要。
    • @Nas 你说的“简化”是什么意思?如果您的简化是 MyClientTask 类,它根本不会像我已经说过的那样工作
    猜你喜欢
    • 2011-03-19
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-23
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多