DatagramSocket Packets由路由器更改的IPAddress?

时间:2016-01-27 23:04:44

标签: java android sockets network-programming datagram

我创建了一个服务器,它将在我的桌面上运行,以便从客户端发送和接收消息。客户端应用程序将在Android上运行。截至目前,两个程序都启动,客户端能够将初始连接发送到服务器。我的桌面通过路由器连接到互联网,我从路由器端口转发以接收信息。

服务器能够接收客户端发送的所有消息。但是,服务器无法响应。我快速检查了收到的数据包(服务器端),并说该数据包的ipaddress是我的路由器的IP。这是否意味着我将无法发送响应,因为我的所有数据包都会将其IP更改为路由器的本地地址(因为端口转发)?

我发布下面的一些代码,虽然我不确定它会有所帮助。非常感谢您的评论。

服务器:

public class QuoteServerThread extends Thread {

protected DatagramSocket socket = null;
DatagramPacket dgp = null;
protected boolean running = true;
ArrayList<ConnectedUser> users = new ArrayList<>();
String state;
int port;
int userId;

public QuoteServerThread(String name, String state) throws IOException {
    super(name);
    port = 4445;
    userId = 1;
    socket = new DatagramSocket(port);
    this.state = state;
    this.state = "listening";
    System.out.println("Server Socket is now listening on port: " + port);
}

public void run() {
    while (running) {
        try {
            byte[] buf = new byte[256];

            // receive request
            final DatagramPacket packet = new DatagramPacket(buf, buf.length);
            socket.receive(packet);
            if(packet.getData() == null){
                System.out.println(packet.getData());
                return;
            }
            else{
                System.out.println(packet.getData());
            }
            dgp = packet;
            String message = new String(packet.getData(), 0, packet.getLength());

            if(state.equals("listening")) {
                if(message.contains("newUser")){
                    ConnectedUser newUser = new ConnectedUser(userId, socket);
                    users.add(newUser);
                    System.out.println("connected users: " + users.size());

                    String msg = "ID/" + userId;

                    InetAddress IPAddress = packet.getAddress();
                    int _port = packet.getPort();
                    System.out.println(IPAddress + "," + _port);
                    DatagramPacket out = new DatagramPacket(msg.getBytes(), msg.length(), IPAddress, _port);
                    socket.send(out);

                    userId++;
                }
                else if(message.contains("ID/")){
                    String receivedMessage[] = message.split("/");

                    System.out.println(receivedMessage[0] + ", " + receivedMessage[1] + ", " + receivedMessage[2]);
                }
                else{
                    System.out.println(message);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
            running = false;
        }
    }
    socket.close();
}

}

客户端:

public class QuoteServerThread extends Thread {

protected DatagramSocket socket = null;
protected boolean running = true;
TextView chatWindow;
TextView notification;
EditText chatBox;
MainActivity ma;
ScrollView sv;

public QuoteServerThread(MainActivity ma, TextView chatWindow, EditText chatBox, ScrollView sv, TextView notification) throws IOException {
    this("QuoteServerThread");
    this.ma = ma;
    this.chatWindow = chatWindow;
    this.sv = sv;
    this.chatBox = chatBox;
    this.notification = notification;
}

public QuoteServerThread(String name) throws IOException {
    super(name);
    socket = new DatagramSocket();
}

public void run() {
    while (running) {
        try {
            byte[] buf = new byte[256];

            // receive request
            final DatagramPacket packet = new DatagramPacket(buf, buf.length);
            socket.receive(packet);

            if(packet.getData() == null){
                System.out.println("data was null!");
                return;
            }

            String message = new String(packet.getData(), 0, packet.getLength());

            final String notif = message;
            notification.post(new Runnable() {
                public void run() {
                    notification.setText("server " + "__msg: " + notif);
                }
            });


            if(ma.state.equals("connected")) {
                final String chatText = chatWindow.getText().toString() + "\n" + "Sender: " + message;
                chatWindow.post(new Runnable() {
                    public void run() {
                        chatWindow.setText(chatText);
                        sv.post(new Runnable() {
                            public void run() {
                                sv.fullScroll(View.FOCUS_DOWN);
                                chatBox.post(new Runnable() {
                                    public void run() {
                                        chatBox.requestFocus();
                                    }
                                });
                            }
                        });
                    }
                });
            }
            else if(ma.state.equals("waitingconnection")){
                String msgSplit[];
                if(message.contains("ID/")){
                    msgSplit = message.split("/");

                    final String id = msgSplit[1];
                    ma.clientID = Integer.getInteger(id);


                    notification.post(new Runnable() {
                        public void run() {
                            notification.setText("connected to server " + "__msg: " + id);
                            ma.state = "connected";
                        }
                    });
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
            running = false;
        }
    }
    socket.close();
}

}

这里唯一的问题是客户没有收到回复。再次说明问题,我相信我的路由器上的端口转发正在将数据包地址更改为其本地ipaddress(我的手机正在从移动网络发送)。关于如何解决这个问题的任何想法?

2 个答案:

答案 0 :(得分:0)

我认为您正在看到网络地址转换(NAT)和端口转发的影响。从Android客户端的角度来看,它正在与您的路由器进行通信。然后,您的路由器而不是处理消息本身会将处理卸载到您的服务器(端口转发)。

在您的服务器上,您会看到目标地址。由于您的Android客户端正在与您的路由器通信,因此您看到的目标IP地址是路由器的IP地址。

如果您想回复,您应该采取数据报的源地址并将回复发送回该地址。当数据报通过带有NAT的路由器时,它会将源地址更改为路由器的地址。

答案 1 :(得分:0)

上面的问题是由于我在后台运行的代码。发送消息时,我使用的是名为MsgSender的类。但是,MsgSender正在创建一个新套接字并发送数据。发送数据后,它关闭了套接字,不再监听服务器的响应。

为了解决这个问题,我共享了一个打开的套接字,并通过单个套接字发送所有数据,以便它可以侦听返回的任何信息。

请确保在发送信息时,如果您需要侦听响应,则必须通过发送的套接字进行监听。如果您不需要侦听要发送的数据的响应,则可以关闭套接字。