当前位置:   article > 正文

在 IntelliJ IDEA 中远程调试 Java 程序_idea 远程调试java

idea 远程调试java

笔者的运行环境:

  • 客户端

    • 部署成功过的客户端的 Java 版本:

      • Java 11.0.12
    • 部署成功过的客户端的 IntelliJ IDEA 版本:

      • IntelliJ IDEA 2020.1.2 (Ultimate Edition)
    • 部署成功过的客户端的 Windows:

      • Windows 10 教育版
  • 服务端

    • 部署成功过的服务端的 Java 版本:

      • Java 11.0.12
    • 部署成功过的服务端的 Linux:

      • CentOS Stream 8 x86_64

远程调试与远程部署的区别

  在 IntelliJ IDEA 中进行远程调试与远程部署是不同的。

  远程调试指的是事先以其它方法将 Java 应用打包并放在远程服务器中,然后以调试模式运行该 Java 应用,最后使用本地的 IntelliJ IDEA 进行远程连接该应用。

  远程部署指的是直接使用本地的 IntelliJ IDEA 将本地的 Java 应用打包、部署到远程服务器,并远程运行该应用。

  可以看出,远程部署要比远程调试方便很多。但有些环境下,只支持远程调试,而不支持远程部署。本文主要讲远程调试。

  关于在 IntelliJ IDEA 中远程部署 Java 程序,可见笔者的另一篇博客:

  在 IntelliJ IDEA 中远程部署 Java 程序:
https://blog.csdn.net/wangpaiblog/article/details/132820212

IntelliJ IDEA 远程调试的原理

  远程调试指的是使用本地客户端来调试运行在远程服务器上的程序。IntelliJ IDEA 远程调试的原理是,当服务器端以调试模式运行 Java 程序时,如果客户端使用文本相同的字节码和事先约定好的端口号,就可以远程调试该 Java 程序。因此,IntelliJ IDEA 远程调试的必要条件是:

  • Java 程序必须在服务端已经启动且在调试时正在运行。IntelliJ IDEA 只有触发调试的能力,没有远程部署启动 Java 程序的能力

  • Java 程序在服务端以调试模式启动。以调试模式启动需要在运行该 Java 程序时,使用一些调试模式的 JVM 参数。

  • 客户端使用 IntelliJ IDEA 进行调试时,使用与服务端事先约定好的相同端口号,且该端口号在服务端没有被占用。

  • 客户端使用 IntelliJ IDEA 进行调试时,使用的代码在文本上与服务端一致。在文本上一致指的是,客户端使用的代码与服务端使用的代码的文字完全相同,如果不一致,使用的断点将不起作用。文本上一致不包括注释,但包括换行。文本上一致不需要是同一个代码源文件,只需要文本相同即可。


  使用 IntelliJ IDEA 进行远程调试的注意事项:

  • IntelliJ IDEA 只有触发调试的能力,没有远程部署启动 Java 程序的能力。只能自己先确保 Java 程序可以在服务端基本运行之后才能在客户端使用远程调试,无法通过 IntelliJ IDEA 来直接利用服务端的环境运行 Java 代码。

  • 在远程调试时,程序是在服务端运行的,与客户端没有任何关系,产生的数据对客户端不会有任何影响。

  • 代码在文本上与服务端一致 仅指代码相同。文本上一致不包括注释,但包括换行。文本上一致不需要是同一个代码源文件,只需要文本相同即可。也不需要约定 JAR 包名,但需要使用同一标识的应用。

  • 在 IntelliJ IDEA 的代码中打断点不需要在调试之前打断点,只需要在程序运行到此断点之前打即可。一般部署在服务端的应用都是一个无限循环的应用,同一处代码会不断地运行。因此一般可以在调试时的任何时候打断点。

  • 一旦在客户端的 IntelliJ IDEA 中触发了断点,在服务端运行的 Java 程序会立刻被暂停运行,且受客户端的 IntelliJ IDEA 所控制。


  IntelliJ IDEA 远程调试有两种模式,一种是 attach,另一种是 listenattach 指的是服务端的 Java 程序已经运行,使用 IntelliJ IDEA 立即进行调试。listen 指是服务端的 Java 程序可能还没有运行,现在正在监听在服务端的该端口,直到服务端的 Java 程序启动了再触发调试。本文使用的是 attach 模式。

使用 IntelliJ IDEA 远程调试原始 Java 程序的步骤

  1. 为了方便远程输入命令、将文件加入到 Linux 操作系统中,最好还要在一台 Windows 操作系统上面使用一种终端控制软件,如 Xshell、Xftp 等。关于这方面的内容,可见笔者的另一篇如下博客。同时,该博客还给出了查看 Linux 中的 IP 的方法。

    如何在 Windows 主机上访问本地局域网中的 Linux 主机:
    https://blog.csdn.net/wangpaiblog/article/details/120052152

    现在,假设读者已经会了如何将文件从 Windows 中传入 Linux 中,以及查看 Linux 中的 IP。

  2. 为了方便说明,笔者编写了一个傻瓜的 Java 程序。此 Java 程序是在本地的客户端中的 IntelliJ IDEA 中完成编写的。示例代码如下:

    以下代码的简单解释:

    • 以下为无限循环延时代码。间隔时间为 1 秒,每秒会打印循环的圈数。

    • 使用无限循环的原因是,为了确保进行远程调试时,远程程序依然处于运行的状态。

    • 无需为无限循环而担心,因为这里是阻塞型程序,在 Shell 中运行时,使用 ctrl + C 即可立刻终止该程序。

    public class Main {
        public static void main(String[] args) throws InterruptedException {
            System.out.println("--------start--------");
    
            if (args != null && args.length != 0) {
                for (int order = 1; order <= args.length; ++order) {
                    System.out.println(order + ":" + args[order - 1]);
                }
            } else {
                System.out.println("Hello world.");
            }
    
            for (int order = 0; true; ++order) { // 无限循环延时代码
                System.out.println(order);
                Thread.currentThread().sleep(1000); // 休眠 1 秒
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  3. 在 IntelliJ IDEA 中进行远程调试的相关配置。如下图所示进行操作。

    在这里插入图片描述

    在这里插入图片描述

  4. 如下图所示进行操作。注意复制图中的 JVM 代码,这将在之后在服务端用于以调试模式启动本程序。

    笔者示例中约定的端口号为 5005,JVM 代码为:

    -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

    在这里插入图片描述

  5. 在本地客户端制作 JAR 包。

    如果读者没使用 Maven 等构建工具,打包的方法可见笔者的另一篇博客:

    不使用 Maven 等构建工具,而使用原始方法在 IntelliJ IDEA 中制作 JAR 包:
    https://blog.csdn.net/wangpaiblog/article/details/120359856?spm=1001.2014.3001.5501

    如果读者使用了 Maven,则 Maven 下打包的方法可见笔者的另一篇博客:

    将 Maven 中的多模块项目只打成一个 JAR 包:
    https://blog.csdn.net/wangpaiblog/article/details/119628194

  6. 得到 JAR 包之后,可以使用 Xftp 将其上传到服务器端的 Linux 中。

  7. 对于很多 Linux 系统,此时还不能直接进行远程调试,因为 Linux 上有防火墙,默认会阻止所有的远程访问。对于笔者的 CentOS Stream 8 x86_64,默认的防火墙为 firewalld,而不是 iptables。(很多早期的 Linux,使用的防火墙是 iptables,但 RedHat 从 RHEL 7 开始就用 firewalld 取代了 iptables。)

    • 一个偷懒的方法就是,永久地关闭防火墙。关闭的方法如下:

      systemctl stop firewalld

      systemctl mask firewalld

      firewall-cmd --reload

    • 另一个方法是,在防火墙中永久开放上述约定的端口号 5005。开放的方法如下:

      firewall-cmd --zone=public --add-port=5005/tcp --permanent

      firewall-cmd --reload

      单独开放完端口 5005 之后,可以输入以下命令查看是否生效:

      firewall-cmd --zone=public --query-port=5005/tcp

      [root@localhost temp]# firewall-cmd --zone=public --query-port=5005/tcp
      yes
      
      • 1
      • 2

      实际上,也可以输入以下命令查看所有开放的端口:

      firewall-cmd --zone=public --list-ports

      [root@localhost temp]# firewall-cmd --zone=public --list-ports
      5005/tcp
      
      • 1
      • 2
  8. 进入上述 JAR 包的目录。假设上面上传的 JAR 包名为 demo.jar。整合前面复制的 JVM 代码,输入以下命令来运行此 demo 程序。

    java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar demo.jar

  9. 可以看到,前面的无限循环程序开始运行了。

    在这里插入图片描述

  10. 现在就可以在本地客户端的 IntelliJ IDEA 进行远程调试了。

    在这里插入图片描述

  11. 如果远程调试成功。在服务器端运行的上述 Java 程序会立刻被暂停运行。而在 IntelliJ IDEA 的调试控制台 Console 中会有如下显示:

    在这里插入图片描述

  12. 最后,记得去服务器端使用 ctrl + C 终止上述 demo 程序。

  13. 尽管很多读者认真阅读了笔者的教程,但现实中仍然可能出现很多调试失败的例子。当读者远程调试失败的时候,还请再回去看笔者本文前面写的 IntelliJ IDEA 远程调试的原理,不过这里也再提几点:

    • 如果远程服务端的 Java 程序没有启动,这是一定会调试失败的。因为如果远程服务端的 Java 程序没有启动,则远程服务端的端口号会不存在。(这与有没有在防火墙对外开放端口号权限无关。如果远程服务端的 Java 程序没有启动,就会连端口号都没有,开放端口号权限也没用。)

    • 如果想知道远程服务端的端口号有没有生成,可以在远程服务端输入以下命令:(如果运行的程序阻塞了当前的 Shell 窗口,可以在 Xshell 中另开一个 Shell 窗口。)

      netstat -na | grep 5005

      [root@localhost ~]# netstat -na | grep 5005
      tcp        0      0 0.0.0.0:5005            0.0.0.0:*               LISTEN 
      
      • 1
      • 2
    • 如果想知道本地客户端能不能连接远程的端口号,可以在本地客户端输入以下命令:

      ssh -v -p 5005 192.168.0.100

      以笔者在 Windows 的 CMD 中,访问 Linux 的端口号 5005 为例。

      如果访问成功,输出信息为:

      C:\Users\XXXXX>ssh -v -p 5005 192.168.0.100
      OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5
      debug1: Connecting to 192.168.0.100 [192.168.0.100] port 5005.
      debug1: Connection established.
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_rsa type 0
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_rsa-cert type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_dsa type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_dsa-cert type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_ecdsa type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_ecdsa-cert type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_ed25519 type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_ed25519-cert type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_xmss type -1
      debug1: key_load_public: No such file or directory
      debug1: identity file C:\\Users\\XXXXX/.ssh/id_xmss-cert type -1
      debug1: Local version string SSH-2.0-OpenSSH_for_Windows_7.7
      ssh_exchange_identification: read: Connection reset
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25

      如果访问不成功,输出信息为:

      C:\Users\XXXXX>ssh -v -p 5005 192.168.0.100
      OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5
      debug1: Connecting to 192.168.0.100 [192.168.0.100] port 5005.
      debug1: connect to address 192.168.0.100 port 5005: Connection refused
      ssh: connect to host 192.168.0.100 port 5005: Connection refused
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 如果本地 IntelliJ IDEA 中没有使用前述的 在文本上一致 的代码,而其它正确,则远程调试会成功,但断点会打不了(断点不生效)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/613214
推荐阅读
相关标签
  

闽ICP备14008679号