Android java.net.DatagramSocket EPERM(不允许操作)

时间:2018-04-12 23:29:46

标签: java android sockets udp sony

我尝试将我的索尼相机连接到应用程序。 要获取设备信息,我首先需要发送3次数据包,然后等待响应。代码看起来像SDK示例:

int SSDP_MX = 1;
int SSDP_PORT = 1900;
String SSDP_ADDR = "239.255.255.250";

String ssdpRequest =
      "M-SEARCH * HTTP/1.1\r\n" + String.format("HOST: %s:%d\r\n", SSDP_ADDR, SSDP_PORT)
      + String.format("MAN: \"ssdp:discover\"\r\n")
      + String.format("MX: %d\r\n", SSDP_MX)
      + String.format("ST: %s\r\n", SSDP_ST) + "\r\n";

socket = new DatagramSocket();
InetSocketAddress iAddress = new InetSocketAddress(SSDP_ADDR, SSDP_PORT);
packet = new DatagramPacket(sendData, sendData.length, iAddress);
// send 3 times
socket.send(packet);
Thread.sleep(100);
socket.send(packet);
Thread.sleep(100);
socket.send(packet);

我现在的问题是,它有时会完美地工作多次,而另一次EPERM (Operation not permitted)会发生。当这种情况发生时,任即使重新安装应用程序,停止它,重新启动智能手机,错误也会一直发生。 堆栈跟踪:

java.io.IOException: sendto failed: EPERM (Operation not permitted)
    at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:603)
    at libcore.io.IoBridge.sendto(IoBridge.java:571)
    at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:124)
    at java.net.DatagramSocket.send(DatagramSocket.java:721)
    at com.sonyAdvancedRemote.kilian.api.camera.CameraDeviceSearcher$1.run(CameraDeviceSearcher.java:137)
 Caused by: android.system.ErrnoException: sendto failed: EPERM (Operation not permitted)
    at libcore.io.Linux.sendtoBytes(Native Method)
    at libcore.io.Linux.sendto(Linux.java:227)
    at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:304)
    at libcore.io.IoBridge.sendto(IoBridge.java:569)
    at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:124) 
    at java.net.DatagramSocket.send(DatagramSocket.java:721) 
    at com.sonyAdvancedRemote.kilian.api.camera.CameraDeviceSearcher$1.run(CameraDeviceSearcher.java:137) 

Orignial Sony Play Memories Apps似乎使用ScheduledExecutorService执行Runnable发送数据。它也使用MulticastSocket,但我并不完全理解重建它的代码,无论如何我认为我的问题仍然存在,因为我已经尝试使用多播套接字。

任何想法如何解决它?

修改1

因此,我将深入研究官方PlayMemoriesApp的代码。

socket = new MulticastSocket(1900);
mMcInetAddress = InetAddress.getByName(ADD);
socket.joinGroup(mMcInetAddress);

 packet = new DatagramPacket(sendData, sendData.length, iAddress);
                   socket.setNetworkInterface( NetworkInterface.getByName("interfaceName"));
 Runnable sendTask = () -> {
         try {
              socket.send(packet);
              receiveReplyPackets();
                        };
         try {
               this.mScheduledExecutor.execute(sendTask);
               this.mScheduledExecutor.schedule(sendTask, 100, TimeUnit.MILLISECONDS);
               this.mScheduledExecutor.schedule(sendTask, 300, TimeUnit.MILLISECONDS);
         } catch (RejectedExecutionException e) {
                e.printStackTrace();
         }

我的想法是尝试所有不同的网络接口,因为我不是100%确定他们使用哪一个。我最终测试了所有25.有时我可以发送它,但我没有得到服务器的响应,或者我得到Operation permitted错误。

解决方案

经过一番研究后,我发现了这个项目:https://github.com/praetoriandroid/sony-camera-remote-java/blob/master/sony-camera-remote-lib/src/main/java/com/praetoriandroid/cameraremote/SsdpClient.java

那里有什么不同,就是他正在使用另一个socketaddress:

SocketAddress localAddress = new InetSocketAddress(getFirstWiFiAddress(), 0);
socket = new DatagramSocket(localAddress);

private InetAddress getFirstWiFiAddress() {
        String WIFI_INTERFACE_NAME = "^w.*[0-9]$";
        try {
            Enumeration<NetworkInterface> interfaces;
            for (interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements(); ) {
                NetworkInterface networkInterface = interfaces.nextElement();
                if (!networkInterface.getName().matches(WIFI_INTERFACE_NAME)) {
                    continue;
                }

                Enumeration<InetAddress> inetAddresses;
                for (inetAddresses = networkInterface.getInetAddresses(); inetAddresses.hasMoreElements(); ) {
                    InetAddress address = inetAddresses.nextElement();
                    if (!address.isSiteLocalAddress()) {
                        continue;
                    }
                    if (address instanceof Inet4Address) {
                        return address;
                    }
                }
            }
        } catch (SocketException ignored) {

        }
        return null;
    }

0 个答案:

没有答案