端口占用处理机制

397 阅读3分钟

我正在参与掘金创作者训练营第5期,点击了解活动详情

如果我们自己的 Java 程序所使用的端口被占用了,该如何处理?

解决方案如下:

  1. 提示用户端口冲突,软件无法运行。
  2. 自动更换可用的端口,再次运行,即采用动态端口。

很显然我们不可能采取第 1 种方案,这样的软件很不智能。那该如何实现动态端口呢?我们常用的腾讯 QQ,就是采用的动态端口机制,接下来,我们来看端口占用的场景 😀

QQ 在不同的平台下采用的端口机制不一样。Window 和 Linux 平台下直接采用动态端口。Mac 下是固定端口,当端口被占用后,自动更换一个可用的端口。如 4301 端口,如果 4301 被占用,则会更换可用端口,保证 QQ 软件可以正常启动。

QQ 端口演示

在linu环境下,打开终端,输入 qq 来启动

image.png 登录qq后,重新打开一个新终端,然后输入下面的命令查看 QQ 的端口:

netstat -ap

结果如下:

image.png 红色方框内的 47330 是 QQ 的端口。我们现在退出 QQ,然后重新运行 QQ 软件,再次查看 QQ 的端口,如下图所示:

image.png 我们发现 QQ 的端口已经变为了 47390,说明 QQ 在 Ubuntu 平台采用的是动态端口。

采用动态端口目的是防止冲突,影响软件运行。但是当我们自己写的程序所使用的端口如果被占用了,我们又该如何采用动态端口呢?Java 的异常处理机制,可以让我们在端口被占用的时候,在 catch 中进行处理,采用动态端口来保证程序正常运行。

使用异常处理端口占用

我们熟悉的软件 Real VNC Server 的默认端口是 5901,那么现在我们有下面的 Socket 程序,所使用的端口也是 5901,如下所示:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class Port {
    public static void main(String[] args) {
        int port = 5901;
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress("localhost", port));
            System.out.println("开始使用" + port + "监听......");
            socket = serverSocket.accept();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

编译、运行程序,发生了异常,如下图所示:

image.png

提示代码的第 11 行发生了异常,原因就是 5901 端口被占用,我们现在来看是哪个程序占用了 5901 端口,执行下面的命令进行查看:

netstat -ap

结果如下图所示:

image.png

从图中可以看出是 vnc 软件已经使用了 5901 端口导致我们的程序出现了异常。我们必须进行处理,就像 Mac 下的 QQ 一样,端口被占用,就自动加 2。

我们可以利用 Java 的异常处理机制,来解决该问题,发生异常后 catch 会捕获到该异常,然后我们在 catch 中让 port 变量加 1,然后再去执行第 11 行代码,如果此时端口还是被占用,则又进入 catch 中,port 会再次加 1,然后再执行第 11 行代码,直到遇到一个可用的端口。

如何解决?

在原来代码里面进行修改。

public static void main(String[] args) { 
int port = 5901; 
ServerSocket serverSocket = null;
Socket socket = null;
boolean flag = true; 
while (flag) {
try { 
serverSocket = new ServerSocket(); 
serverSocket.bind(new InetSocketAddress("localhost", port));
flag = false;
System.out.println("开始使用" + port + "监听......");
socket = serverSocket.accept();
} catch