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 正在创建一个新套接字并发送数据。发送数据后,它关闭套接字,不再监听服务器的响应。
为了解决这个问题,我共享了保持打开状态的套接字,并通过单个套接字发送所有数据,以便它可以侦听返回的任何信息。
请确保当您发送信息时,如果您需要侦听响应,您必须通过发送信息的套接字进行侦听。如果您不需要侦听来自您将要发送的数据的响应,您可以关闭套接字。
我已经创建了一个服务器,它将在我的桌面上 运行 发送和接收来自客户端的消息。客户端应用程序将在 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 正在创建一个新套接字并发送数据。发送数据后,它关闭套接字,不再监听服务器的响应。
为了解决这个问题,我共享了保持打开状态的套接字,并通过单个套接字发送所有数据,以便它可以侦听返回的任何信息。
请确保当您发送信息时,如果您需要侦听响应,您必须通过发送信息的套接字进行侦听。如果您不需要侦听来自您将要发送的数据的响应,您可以关闭套接字。