2013-02-16 38 views
4

我目前正在研究Java中的UDP数据包传输以在Android上创建多人游戏。 我成功地使用通常的“127.0.0.1”在我的Nexus 4中交换数据包,并且我也成功地在我的PC服务器和我的本地网络中的Android客户端之间交换数据包。 但是因为我希望我的游戏可以在Internet上播放,所以我希望我的Android客户端能够在不在同一本地网络上时与我的PC服务器交换数据包。这是我挣扎的地方。无法通过Internet从PC服务器接收Android上的UDP数据

我的设置:连接家庭Internet连接的PC服务器和连接3G网络的Nexus 4。

首先,我的PC服务器开始监听端口10000,我的Android客户端打开一个套接字接收端口10001上的服务器数据包。然后,Android客户端向PC服务器发送一个数据包到其当前公共地址“173.246。 12.125“。端口1000上的PC服务器收到该数据包并向端口10001发送一个响应。但Android客户端从未收到响应。

这里是我的PC服务器代码:

public class UDPServer { 
    private final static int SERVER_PORT = 10000; 
    private final static int CLIENT_PORT = 10001; 

    public static void main(String[] args) { 
     InetAddress clientAddr = null; 
     DatagramSocket socket = null; 
     try { 
      //Initializing the UDP server 
      System.out.println(String.format("Connecting on %s...", SERVER_PORT)); 
      socket = new DatagramSocket(SERVER_PORT); 
      System.out.println("Connected."); 
      System.out.println("===================="); 
     } catch (UnknownHostException e1) { 
      e1.printStackTrace(); 
     } catch (SocketException e) { 
      e.printStackTrace(); 
     } 

     while(true){ 
      try { 
       //Listening 
       byte[] buf = new byte[1024]; 
       DatagramPacket packet = new DatagramPacket(buf, buf.length); 
       System.out.println("Listening..."); 
       socket.receive(packet); 

       //Getting client address from the packet we received 
       clientAddr = packet.getAddress(); 
       System.out.println("Received: '" + new String(packet.getData()).trim() + "' from "+clientAddr.toString()); 

       //Sending response 
       byte[] message = ("Hello Android").getBytes(); 
       DatagramPacket response = new DatagramPacket(message, message.length, clientAddr, CLIENT_PORT); 
       DatagramSocket clientSocket = new DatagramSocket(); 
       System.out.println("Sending: '" + new String(message) + "'"); 
       clientSocket.send(response); 
       System.out.println("Response sent."); 
       System.out.println("--------------------"); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

这里是我的Android客户端类:

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new Thread(new Receiver()).start(); 
     try { 
      Thread.sleep(500); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     new Thread(new Client()).start(); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.activity_main, menu); 
     return true; 
    } 

} 

public class Receiver implements Runnable { 
    private final static int LISTENING_PORT = 10001; 

    @Override 
    public void run() { 
     try { 
      //Opening listening socket 
      Log.d("UDP Receiver", "Opening listening socket on port "+LISTENING_PORT+"..."); 
      DatagramSocket socket = new DatagramSocket(LISTENING_PORT); 
      socket.setBroadcast(true); 
      socket.setReuseAddress(true); 

      while(true){ 
       //Listening on socket 
       Log.d("UDP Receiver", "Listening..."); 
       byte[] buf = new byte[1024]; 
       DatagramPacket packet = new DatagramPacket(buf, buf.length); 
       socket.receive(packet); 
       Log.d("UDP", "Received: '" + new String(packet.getData()).trim() + "'"); 
      } 
     } catch (Exception e) { 
      Log.e("UDP", "Receiver error", e); 
     } 
    } 
} 

public class Client implements Runnable { 
    private final static String SERVER_ADDRESS = "173.246.12.125";//public ip of my server 
    private final static int SERVER_PORT = 10000; 

    @Override 
    public void run() { 
     try { 
      //Preparing the socket 
      InetAddress serverAddr = InetAddress.getByName(SERVER_ADDRESS); 
      DatagramSocket socket = new DatagramSocket(); 

      //Preparing the packet 
      byte[] buf = ("Hello computer").getBytes(); 
      DatagramPacket packet = new DatagramPacket(buf, buf.length, serverAddr, SERVER_PORT); 

      //Sending the packet 
      Log.d("UDP", String.format("Sending: '%s' to %s:%s", new String(buf), SERVER_ADDRESS, SERVER_PORT)); 
      socket.send(packet); 
      Log.d("UDP", "Packet sent."); 
     } catch (Exception e) { 
      Log.e("UDP", "Client error", e); 
     } 
    } 
} 

服务器的控制台中显示客户端的IP:

Connecting on 192.168.1.126:10000... 
Connected. 
==================== 
Listening... 
Received: 'Hello computer' from /204.48.72.68 
Sending: 'Hello Android' 
Response sent. 
-------------------- 
Listening... 

包似乎来自地址204.48.72.68,但如果我在我的Android上继续whatismyip.com,它显示m e 96.22.246.97 ...我不知道204.48.72.68是从哪里来的......

我不确定问题是我的Android客户端上的监听套接字不好还是PC服务器不会将响应发送到正确的地址。 有人能指出我做错了什么吗?

谢谢

+0

您可能在生命周期http://developer.android.com/reference/android/app/Activity中遇到问题。html#ProcessLifecycle – 2013-02-16 21:57:13

+0

如果我明白你在告诉我什么,即使我的接收器在新线程中运行,并且应用在创建活动时发送它的消息,Android可能会在ms创建之后在我的接收器中终止接收器的进程活动? – 2013-02-16 22:10:23

+0

我不是专家,但类似的事情可能正在发生。也许一些打印输出或调试将证明是有用的。 – 2013-02-16 23:32:54

回答

1

我遇到了类似的问题来了,但是我用的是TCP套接字,而不是UDP的。我的激情是直接发送文件到手机。在局域网中,这非常有效。 看来,当您的手机使用移动连接连接到互联网时,无法将数据发送到监听套接字。 我已阅读过一些页面(sry没有任何链接),移动电话上的传入连接被电信提供商阻止。 我的解决方法是创建到服务器的传出连接并使用tcp套接字的双向可能性。 也许你可以使用你的“工作”数据报套接字,与你的手机交换数据。 下面是一个例子,我发现了:当仿真器,但它工作正常试过,如果你使用任何Android手机 http://itucet.blogspot.de/2011/03/java-bidirectional-data-transfer-using.html

+0

感谢您的回应,我不知道阻止传入连接的电信提供商!我知道我们可以使用TCP连接,因为它们保持活着,但我选择使用UDP来更快地进行数据包交换。你能描述一下我可以使用的“工作”数据报套接字吗? PS:这个例子就是我在单台计算机上同时测试服务器和客户端时使用的。 – 2013-02-17 00:34:58

+0

我的意思是重复使用相同的DatagramSocket,它已将Hello Computer发送到服务器。虽然您使用的是不同的线程,但您可以使用相同的套接字。不知道这是否会满足您的需求,我只是想介意它。 – lunatikz 2013-02-17 02:21:33

+0

我也读过http://stackoverflow.com/questions/5904820/android-udp-communication,但它没有为我工作。我想这是因为我的服务器收到的数据包的IP地址不是我手机的真实IP地址。在我的电信提供商的基础架构中似乎存在阻塞。 – 2013-02-17 03:34:44

1

相同的代码为我工作很好,有一个问题。

问题的原因是android模拟器和你的电脑不在同一个子网。

+0

我没有使用Android模拟器,我认为问题在于我的Android手机所连接的网络阻塞了我的服务器试图建立的连接。 UPD不能用于每个电信网络。 – 2013-05-16 12:45:42