Java 无法在Android上通过Internet从PC服务器接收UDP数据

Java 无法在Android上通过Internet从PC服务器接收UDP数据,java,android,udp,Java,Android,Udp,我目前正在探索Java中的UDP数据包传输,以便在Android上创建一个多人游戏。 通过使用通常的“127.0.0.1”,我成功地在Nexus4中交换了数据包,并且在本地网络中的PC服务器和Android客户端之间也成功地交换了数据包。 但由于我希望我的游戏可以在互联网上玩,我希望我的Android客户端能够在我的PC服务器不在同一个本地网络上时与它们交换数据包。这就是我努力奋斗的地方 我的设置:一台PC服务器与我的家庭互联网连接,一台Nexus 4与3G网络连接 首先,我的PC服务器开始监听

我目前正在探索Java中的UDP数据包传输,以便在Android上创建一个多人游戏。 通过使用通常的“127.0.0.1”,我成功地在Nexus4中交换了数据包,并且在本地网络中的PC服务器和Android客户端之间也成功地交换了数据包。 但由于我希望我的游戏可以在互联网上玩,我希望我的Android客户端能够在我的PC服务器不在同一个本地网络上时与它们交换数据包。这就是我努力奋斗的地方

我的设置:一台PC服务器与我的家庭互联网连接,一台Nexus 4与3G网络连接

首先,我的PC服务器开始监听端口10000,我的Android客户端打开一个套接字以接收端口10001上的服务器数据包。然后,Android客户端向PC服务器发送一个数据包到端口10000上的当前公共地址“173.246.12.125”。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,它会显示96.22.246.97。。。我不知道204.48.72.68是从哪里来的

我不确定问题是我的Android客户端上的监听插座不好,还是PC服务器没有将响应发送到正确的地址。 有人能告诉我我做错了什么吗


谢谢

我遇到了类似的问题,但我使用的是TCP套接字而不是UDP。我的工作是直接将文件发送到手机。在局域网中,这非常有效。 当您的手机使用移动连接连接到互联网时,似乎无法将数据发送到监听插座。 我在一些页面上读到(sry不再有任何链接),移动电话的传入连接被电信提供商阻止。 我的解决方法是创建到服务器的传出连接,并使用tcp套接字的双向可能性。 也许你可以使用你的“工作”数据报插座,与你的手机交换数据。 下面是我发现的一个例子:

同样的代码对我来说效果很好,在使用emulator时出现问题,但如果您使用任何android手机,它都可以正常工作


出现此问题的原因是android emulator和您的计算机不在同一子网中。

如果我理解您的意思,您可能会在生命周期中遇到问题,即使我的接收器在新线程中运行,并且应用程序在创建活动时发送消息,Android可能会在创建活动后杀死我的ms内的接收器进程?我不是专家,但类似的事情可能正在发生。也许一些打印输出或调试会被证明是有用的。我可以确认这不是问题所在,我只是将侦听套接字的超时设置为3000ms,3秒钟后会弹出超时异常,因此线程仍然处于活动状态。问题出在其他地方。感谢您的回复,我不知道电信供应商在哪里阻止传入连接!我知道我们可以使用TCP连接,因为它们保持活动状态,但我选择使用UDP来实现更快的数据包交换。你能描述一下我可以使用的“工作”数据报套接字是什么吗?PS:这个例子就是我在一台计算机上测试服务器和客户端时使用的。我的意思是重复使用相同的DatagramSocket,它将Hello计算机发送到服务器。尽管使用不同的线程,但可以使用相同的套接字。我不确定这是否能满足你的需要,我只是想提醒一下。我也读了这篇文章,但它对我不起作用。我想这是因为我的服务器接收到的数据包的ip地址不是我手机的真实ip地址。在我的电信提供商的基础设施中似乎有一个阻塞。我也有相同的pblm…我正在通过pc发送udp数据包,并在android中使用3g进行监听,但3g不起作用,但是当我通过wifi连接安卓设备时,安卓能够接收udp数据包……是否有任何解决方案?我没有使用安卓仿真器,我认为问题在于我的安卓手机连接的网络阻塞了我的服务器试图建立的连接。UPD不能适用于所有的电信网络。