【发布时间】:2014-09-21 05:58:01
【问题描述】:
我在 Android 应用程序和 Python 服务器之间编写了一个简单的 UDP 传输。我知道系统正在运行,因为当我尝试连接本地 IP 地址 (192.168.X.X) 时,会发送和接收正确的消息。但是,当我尝试使用公共 IP 地址时,这不起作用。有谁知道为什么以及如何尝试解决此问题?
我正在尝试实现 UDP 打孔,让服务器充当 Android 客户端的目标客户端,但我无法将第二个客户端的 UDP 数据包发送到 Android 客户端,它永远不会被 Android 端接收。让第二台机器作为第二台客户端来解决这个问题,还是我的代码不完整?
我的提供商 (T-Mobile) 对 UDP 数据包通信是否重要?
客户端(安卓):
public class CustomizeGatewayActivity extends ActionBarActivity {
AsyncUDPReceiver aReceive = null;
static TextView recieve = null;
public static class PlaceholderFragment extends Fragment {
EditText addressText, portText, messageText;
Button udpsend, tcpsend;
Socket socket = null;
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_customize_gateway, container, false);
recieve = (TextView) rootView.findViewById(R.id.textView1);
addressText = (EditText) rootView.findViewById(R.id.editText1);
messageText = (EditText) rootView.findViewById(R.id.editText3);
udpsend = (Button) rootView.findViewById(R.id.UDP);
udpsend.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
AsyncUDPSend aSend = new AsyncUDPSend(addressText.getText().toString(), messageText.getText().toString());
aSend.execute();
}
});
public class AsyncUDPSend extends AsyncTask<Void, Void, Void> {
String address = "";
String message = "";
String response = "";
AsyncUDPSend(String addr, String mes) {
address = addr;
message = mes;
}
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
DatagramSocket dsocket = null;
try {
dsocket = new DatagramSocket();
dsocket.setSoTimeout(10000);
InetAddress dest = InetAddress.getByName(address);
DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), dest, 5001);
dsocket.send(packet);
System.out.println("Sent");
byte[] resp = new byte[1024];
DatagramPacket recv = new DatagramPacket(resp, resp.length);
System.out.println("Waitng for Response");
dsocket.receive(recv);
System.out.println("Received");
response = new String(recv.getData());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
System.out.println(response);
} finally {
if (dsocket != null) {
dsocket.close();
}
}
return null;
}
@Override
protected void onPostExecute(Void result) {
recieve.setText(response);
super.onPostExecute(result);
}
}
@Override
protected void onResume() {
super.onResume();
aReceive = new AsyncUDPReceiver();
aReceive.start();
}
@Override
protected void onPause() {
super.onPause();
aReceive.kill();
}
public class AsyncUDPReceiver extends Thread {
boolean keepRunning = true;
String response = "";
Runnable updateText = new Runnable(){
public void run() {
if(aReceive == null && recieve == null)
return;
recieve.setText(response);
}
};
public void run() {
android.os.Debug.waitForDebugger();
System.out.println("running");
DatagramSocket dsock = null;
byte[] message = new byte[1024];
DatagramPacket dpack = new DatagramPacket(message, message.length);
try {
dsock = new DatagramSocket(5002);
System.out.println(dsock.toString());
while(keepRunning) {
dsock.receive(dpack);
response = new String(dpack.getData());
System.out.println(response);
runOnUiThread(updateText);
}
} catch (SocketException e) {
// TODO Auto-generated catch block
response = "SocketException: " + e.toString();
System.out.println(response);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
response = "IOException: " + e.toString();
System.out.println(response);
e.printStackTrace();
} finally {
if(dsock != null)
dsock.close();
}
}
public void kill() {
keepRunning = false;
}
}
}
服务器(Python):
class ThreadedUDPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip().decode("utf-8")
print("{} Recieved: ".format(self.client_address) + data)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
response = data.upper()
sock.sendto(bytes(response, "utf-8"), self.client_address)
print("{} Sent: {}".format(self.client_address,response))
class ThreadedUDPServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
pass
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "", 5000
udpserver = ThreadedUDPServer((HOST,PORT+1), ThreadedUDPRequestHandler)
udp_thread = threading.Thread(target=udpserver.serve_forever)
udp_thread.daemon = True
udp_thread.start()
print("UDP serving at port", PORT+1)
while True:
pass
udpserver.shutdown()
【问题讨论】:
-
查看我对类似问题的回答 [此处][1] [1]:stackoverflow.com/a/25095781/3199595
-
我意识到 NAT 引起了我的问题,我想实现 UDP 打孔来克服阻塞的数据包,但即使 Android 和服务器相互发送 UDP 数据包,只有Android 可以通过服务器,而服务器永远不会到达 Android 客户端。您是否知道任何解决方案,或者您可以向我推荐一些寻找答案的方向吗?
-
啊,这让我想到了我写的另一个答案:stackoverflow.com/a/25096374/3199595 至于 NAT 遍历技术,我将从查看为您工作的现有框架开始。编写打孔或实现像 IGD (en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol) 这样的协议是一件痛苦的事情。我假设 android 有一个现有的解决方案,因为谷歌确实推送通知(从服务器到 android 设备的通知,其中一些可能在 NAT 之后)
标签: android python sockets udp datagram