我尝试将我的索尼相机连接到应用程序。 要获取设备信息,我首先需要发送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
错误。
解决方案
那里有什么不同,就是他正在使用另一个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;
}