DatagramSocket 数据包 IP 地址被路由器更改?

DatagramSocket Packets IPAddress being changed by router?

我已经创建了一个服务器,它将在我的桌面上 运行 发送和接收来自客户端的消息。客户端应用程序将在 android 上 运行。到目前为止,两个程序都启动了,客户端可以向服务器发送初始连接。我的桌面通过路由器连接到互联网,我从路由器转发端口以接收信息。

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

我将在下面 post 一些代码,尽管我不确定它是否有用。非常感谢您的意见。

服务器:

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();
}

}

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

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

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

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

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

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

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