在Java中使用外部IP地址建立连接

7
我正在尝试构建一个聊天程序,代码已经完成并且当我使用本地计算机并且连接到127.0.0.1时,一切运行良好。我还成功连接了我的笔记本电脑和我的计算机,在同一个路由器上运行(我使用了内部IP地址,10.0.0.3)。现在,我正试图在我的路由器和其他路由器之间建立连接。为此,我正在尝试连接到外部IP地址。我通过我的路由器进行端口转发,并设置了静态IP。然而,当我运行代码时,我总是收到“连接被拒绝”的错误信息。
以下是代码:
MainServer.java:
import java.util.*;
import java.io.*;
import java.net.*;

public class MainServer {
  private ArrayList<Socket> sockets;
  public MainServer() {
    ServerSocket server_socket;
    try {
      server_socket = new ServerSocket(5005);
      sockets = new ArrayList<Socket>();
      System.out.println("server is now running");
      while(true) {
        Socket socket = server_socket.accept();
        sockets.add(socket);
        try {
          PrintWriter writer = new PrintWriter(socket.getOutputStream());
          writer.println("---you are connected to the server---\r\n");
          writer.flush();
        } catch(Exception e) {e.printStackTrace();}
        System.out.println("server connected to " + socket.getInetAddress());
        Reader reader = new Reader(socket);
        Thread thread = new Thread(reader);
        thread.start();
      }
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    MainServer server = new MainServer();
  }
  class Reader implements Runnable {
    Socket socket;
    public Reader(Socket socket) {
      this.socket=socket;
    }
    public void run() {
      while(true) {
        try {
          InputStreamReader stream_reader = new InputStreamReader(socket.getInputStream());
          BufferedReader reader = new BufferedReader(stream_reader);
          while(true) {
            String str = reader.readLine();
            if(str==null)
              continue;
            System.out.println("message from the client " + socket.getInetAddress() + ": " + str);
            send_back_message(str);
          }
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
    public void send_back_message(String str) {
      try {
        for(Socket send_to_socket: sockets) {
          PrintWriter writer = new PrintWriter(send_to_socket.getOutputStream());
          writer.println(send_to_socket.getInetAddress()+ ": " + str);
          writer.flush();
        }
      } catch(Exception e) {e.printStackTrace();}
    }
  }
}

Client.java:

public Client() {
  frame = new JFrame();
  JPanel panel = new JPanel();
  chat = new JTextArea(20,40);
  chat.setEditable(false);
  JScrollPane scroll = new JScrollPane(chat);
  text = new JTextField(32);
  JButton send = new JButton("Send");
  send.addActionListener(new SendButtonListener());
  panel.add(scroll);
  panel.add(text);
  panel.add(send);
  frame.getContentPane().add(panel);
  frame.setSize(500,500);
  frame.setVisible(true);
  try {
    socket = new Socket("77.126.189.65",5005);
  } catch (Exception e) {
    e.printStackTrace();
  }
  Thread thread = new Thread(new ClientReader());
  thread.start();
}
public static void main(String[] args) {
  Client client = new Client();
}
class SendButtonListener implements ActionListener {
  public void actionPerformed(ActionEvent e) {
    try {
      PrintWriter writer = new PrintWriter(socket.getOutputStream());
      writer.println(text.getText());
      writer.flush();
      text.setText("");
    } catch (IOException e1) {
      e1.printStackTrace();
    }
  }
}
class ClientReader implements Runnable {
  public void run() {
    try {
      InputStreamReader stream_reader = new InputStreamReader(socket.getInputStream());
      BufferedReader reader = new BufferedReader(stream_reader);
      while(true) {
        String str = reader.readLine();
        if(str==null)
          continue;
        chat.setText(chat.getText() + str + "\r\n" );
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
}

我也尝试了这个工具。当我运行MainServer文件并使用该工具时,我得到了一个肯定的答案。我自己的Eclipse也是如此。当我的MainServer建立成功连接时,它会使用以下代码打印一条消息:

Socket socket = server_socket.accept();
System.out.println("server connected to " + socket.getInetAddress());

每次我点击上面工具中的”check”按钮时,在我的Eclipse控制台(system.out.println部分)都会收到一条消息:

server connected to /69.163.149.200

因此,我认为问题可能与MainServer、端口转发/防火墙/静态IP等方面无关。
我还想到,问题可能是由于我尝试从自己的路由器设备连接到自己的路由器导致的。如果有人能在他的计算机上运行Client.java,我将保持MainServer文件打开半个小时,这将非常有帮助。

在你的测试中...客户端和服务器都在同一个路由器后面吗? - Davide Berra
是的,我在同一台电脑上使用同一个 Eclipse 和同一个路由器运行服务器和客户端。 - Shelef
如果您仍然在局域网内(据我所知),则必须使用内部IP。如果您在同一台计算机上,则必须使用127.0.0.1。 - Mateusz Krzaczek
我不太明白什么是局域网。我已经使用了内部IP并且它可以工作。程序的主要目的是在不同的路由器之间建立连接,因此我使用外部IP。我正在尝试仅在自己的计算机上建立连接,以检查当我使用外部IP时程序是否能正常工作。 - Shelef
4个回答

4
你想做的事有点奇怪,但是可以实现。
你只需要知道你的路由器是否支持NAT Loopback / NAT Reflection并激活它即可。 NAT-loopback 也称为NAT-hairpinning或NAT-reflection。NAT-loopback是许多普通路由器中的功能,允许用户从LAN网络内部连接到自己的公共IP地址。当网站(带有域名)托管在该IP地址上时,这尤其有用。

1
好的,谢谢。实际上我并不想这样做。但现在我明白了,我不能将路由器默认连接到自己,这就是程序无法工作的原因。 - Shelef
顺便问一下,我如何购买或获取一个可以运行Java文件的服务器,最好类似于网站托管的那种。 - Shelef
1
抱歉... 我不知道... 我在谷歌上快速搜索了一下,出现了成千上万的结果,但我没有关于Java托管的经验 =( - Davide Berra

0

如果您不适当地配置路由器,将无法完成此操作。大多数路由器默认情况下不允许外部(WAN)端口的传入连接。如果您想允许此操作,则需要进入路由器配置并将其配置为允许在特定端口上的外部IP上进行连接。然后,您需要将路由器配置为将来自外部IP地址/端口的传入连接重定向到实际服务器的内部IP地址/端口。

这通常是在线游戏玩家在自己的家中设置服务器的方式。这也是许多人从外部世界连接到自己的内部网络的方式。


你的服务器上完全没有运行防火墙吗? - mightyrick
我不这么认为。根据这个工具,我的端口是开放的:http://www.yougetsignal.com/tools/open-ports/ - Shelef
你能否在自己的电脑上尝试运行Client.java文件,我将会知道它是否可以连接(我的服务器已经开启)。 - Shelef
1
人们不应该像这样请求未知方连接到他们的内部机器。存在安全问题。 - mightyrick
好的,抱歉问了。实际上有人连接到我并写了一些东西。 - Shelef

0

您可以将您的内部IP地址与服务器名称添加到/etc/hosts中,例如,如果您有外部IP 10.10.123.123,并且使用服务器名称YOURCOMPUTER_1.XXX.XXX想要连接内部网络,您可以添加:

127.0.0.1 YOURCOMPUTER_1.XXX.XXX 到您的/etc/hosts文件中。


0

首先,设置一个静态IP地址(例如192.168.1.6)。

如果您想通过外部IP连接,有两种方法:

  1. 如果您有路由器,请使用端口转发。

  2. 如果您有一个数据卡,无需进行端口转发;您可以直接访问服务器。只需提供数据卡的外部IP地址(要查找,请使用类似this one的what's-my-IP服务)和端口号(任意)。 (数据卡不受任何ISP阻止。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接