我正在一个项目中,我的android应用程序应充当其他android客户端的服务器..我正在使用Eneter messaging framework,它在wifi上使用Sockets和Google Protobuf ..一旦我切换到3g网络(尝试使用电话的3g公共ip地址和端口80/81启动服务器),我会收到以下错误消息:EACCES(权限被拒绝)
E/EneterMessaging: ~24216 eneter.messaging.messagingsystems.tcpmessagingsystem.internal.TcpListenerProvider.startListening TcpListenerProvider failed to start listening.
Exception:
java.net.BindException: bind failed: EACCES (Permission denied)
libcore.io.IoBridge.bind(IoBridge.java:99)
java.net.PlainSocketImpl.bind(PlainSocketImpl.java:132)
java.net.ServerSocket.bind(ServerSocket.java:335)
eneter.messaging.messagingsystems.tcpmessagingsystem.NoneSecurityServerFactory.createServerSocket(NoneSecurityServerFactory.java:51)
eneter.messaging.messagingsystems.tcpmessagingsystem.internal.TcpListenerProvider.startListening(TcpListenerProvider.java:123)
eneter.messaging.messagingsystems.tcpmessagingsystem.TcpInputConnector.startListening(TcpInputConnector.java:134)
eneter.messaging.messagingsystems.simplemessagingsystembase.internal.DefaultDuplexInputChannel.startListening(DefaultDuplexInputChannel.java:96)
eneter.messaging.infrastructure.attachable.internal.AttachableDuplexInputChannelBase.attachDuplexInputChannel(AttachableDuplexInputChannelBase.java:40)
com.inactivity.magamine.teatime.services.TCPService.StartServer(TCPService.java:261)
com.inactivity.magamine.teatime.services.TCPService$6.run(TCPService.java:279)
java.lang.Thread.run(Thread.java:818)
我的清单中有以下权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
这是启动服务器的代码:
public void StartServer() throws Exception
{
// Create sender sending MyRequest and as a response receiving MyResponse
// Instantiate Protocol Buffer based serializer.
ISerializer aSerializer = new ProtoBufSerializer();
// Create sender sending MyRequest and as a response receiving MyResponse
// The sender will use Protocol Buffers to serialize/deserialize messages.
IDuplexTypedMessagesFactory aRecieverFactory = new DuplexTypedMessagesFactory(aSerializer);
myReceiver = aRecieverFactory.createDuplexTypedMessageReceiver(MessageDeclarations.MyMsg.class, MessageDeclarations.MyMsg.class);
myReceiver.messageReceived().subscribe(myOnRequestHandler);
if(aMessaging == null)aMessaging = new TcpMessagingSystemFactory();
IDuplexInputChannel anInputChannel
= aMessaging.createDuplexInputChannel(Service_URL);//Service_URL = "tcp://xxx.xxx.x.xx:80/ with public ip adress
// Attach the output channel to the sender and be able to send
// messages and receive responses.
myReceiver.attachDuplexInputChannel(anInputChannel);
isConnected = true;
showNotification("Server Started","url: "+Service_URL,Color.GREEN);
}
该异常发生在
myReceiver.attachDuplexInputChannel(anInputChannel);
那是Eneter启动套接字服务器的地方。
编辑:从this中,我发现要绑定<1024端口需要root特权。因此,我尝试使用1025、8080、8081这样的端口 而是出现以下例外情况:无法分配请求的地址,是 我不能使用3G网络公共IP地址启动套接字服务器 还是我错过了什么?
E/EneterMessaging: ~25710 eneter.messaging.messagingsystems.simplemessagingsystembase.internal.DefaultDuplexInputChannel.startListening DefaultDuplexInputChannel 'tcp://105.66.131.38:8080/' failed to start listening.
Exception:
java.net.BindException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
libcore.io.IoBridge.bind(IoBridge.java:99)
java.net.PlainSocketImpl.bind(PlainSocketImpl.java:132)
java.net.ServerSocket.bind(ServerSocket.java:335)
eneter.messaging.messagingsystems.tcpmessagingsystem.NoneSecurityServerFactory.createServerSocket(NoneSecurityServerFactory.java:51)
eneter.messaging.messagingsystems.tcpmessagingsystem.internal.TcpListenerProvider.startListening(TcpListenerProvider.java:123)
eneter.messaging.messagingsystems.tcpmessagingsystem.TcpInputConnector.startListening(TcpInputConnector.java:134)
eneter.messaging.messagingsystems.simplemessagingsystembase.internal.DefaultDuplexInputChannel.startListening(DefaultDuplexInputChannel.java:96)
eneter.messaging.infrastructure.attachable.internal.AttachableDuplexInputChannelBase.attachDuplexInputChannel(AttachableDuplexInputChannelBase.java:40)
com.inactivity.magamine.teatime.services.TCPService.StartServer(TCPService.java:261)
com.inactivity.magamine.teatime.services.TCPService$6.run(TCPService.java:279)
java.lang.Thread.run(Thread.java:818)
感谢您的帮助。
亲切
答案 0 :(得分:1)
原始问题的答案
端口分配失败,因为您注意到80是特权端口。
回答更新的问题
IP地址分配失败,因为事实证明,您在代码中输入了错误的IP地址。一旦关闭Wi-Fi网络(大概)进入移动网络,您正在使用的地址就会从系统中删除,并且无线运营商会为您分配其他地址。实际上,使用0.0.0.0会告诉您的服务器库“我想在所有接口上进行监听”。 (另一种选择是找出您的移动IP地址,然后使用它。)但是,这使我们遇到了最后一个问题:
对您当前问题的评论
它没有连接可能有很多原因。我怀疑它可能是NAT,如this question中所述。长话短说,很少有应用程序(如果有)使用您选择的体系结构(在连接到移动网络的订户手机上运行服务器)。由于存在NAT,手机几乎总是必须“拨出”才能形成连接(在移动网络上)。而且您的服务器没有拨出;在听。
只要您未跨越NAT边界,这些限制将不适用于您的本地WiFi网络。
要解决此问题,您可能需要了解网络体系结构以及一些网络调试方面的培训。诸如Wireshark之类的捕获工具是一个很大的帮助。
如果您需要更多帮助,而SO上的其他答案都没有帮助,那么最好是提一个新问题。
答案 1 :(得分:1)
更新:我已修复
感谢您的澄清,link 有用。
从wifi切换到3G后,网络运营商会为电话分配一个专用IP地址10.xx.xx.xx,该地址随后会由NAT转换为共享的公共IP地址。
如果所有节点(试图互相连接的电话)都在同一ISP上,并且-(不确定此节点的有效性)-与我的情况相对接近,使用应该使用分配的ISP地址(在我的情况下为10.xx.xx.xx )代替公用IP地址。
我用它来获取有效的IP地址:
public String getAndroidIP() {
try {
String interfaces = "";
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf
.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()
&& inetAddress instanceof Inet4Address) {
interfaces = interfaces
+ inetAddress.getHostAddress().toString();
Log.d("interface NET",interfaces);
}
Log.d("interface Adress",inetAddress.getHostAddress().toString());
}
}
return (interfaces);
} catch (SocketException ex) {
Log.d("getAndroidIP", ex.toString());
}
return null;
}
但是,我应该在不同的运营商和不同的环境下对其进行测试 确保手机不会共享同一3G天线的位置。生病 当我得到结果时对其进行编辑。
谢谢。