BindException: 地址已在使用中,即使端口是唯一的

8

我昨天提出了这个问题,但是没有人能够找出我的问题。因此,我希望提供一个更加最新的代码,并加入昨天的建议。基本上,我一直在试图在服务器和客户端之间建立连接,但无论何时我执行服务器然后执行客户端,我都会得到这个异常:Address already in use。显而易见的答案是给它一个新的端口,但即使这样我仍然会收到这个错误。我认为这与我的代码有关。请问有人能发现吗?我已经附上了服务器类和客户端类。

这是我得到的错误:

Exception in thread "main" java.net.BindException: Address already in use
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:376)
    at java.net.ServerSocket.bind(ServerSocket.java:376)
    at java.net.ServerSocket.<init>(ServerSocket.java:237)
    at java.net.ServerSocket.<init>(ServerSocket.java:128)
    at MessageServer.main(MessageServer.java:16)

服务器代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;

public class MessageServer {

    public static void main(String[] args) throws IOException {
        try {
            int port = 53705;

            ServerSocket server = new ServerSocket(port);

            while (true) {
                System.out.println("Waiting for client...");
                //server.setReuseAddress(true);
                Socket client = server.accept();

                System.out.println("Client from " + server.getInetAddress() + " connected.");
                BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                String inputLine = in.readLine();
                System.out.println("Client said: '"+inputLine+"'");
                Writer count = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
                byte c [] = count.toString().getBytes();
                count.flush();
                count.close();
                in.close();
            } 
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}

客户端代码:

import java.net.*;
import java.io.*;

public class MessageSendClient {

    public static void man(String args[]) throws IOException {
        String servername = "localhost";
        int port = 53705;
        Socket server;
        //server.setReuseAddress(true);
        try {
            server = new Socket (servername,port);

            System.out.println("Connected to " + server.getInetAddress());
            DataInputStream in = new DataInputStream(new BufferedInputStream(server.getInputStream()));

            server.close();
            byte c[] = new byte[100];
            int num = in.read(c);
            String count = new String(c);

            System.out.println("Server said: " + count);

        } catch (Exception e) { }
    }
}

你需要展示实际的堆栈跟踪,并确定程序中抛出异常的语句。 - Jim Garrison
@JimGarrison 你好,我已经在我的帖子中编辑了堆栈跟踪信息。请问您能否看出我的代码哪里有问题吗?谢谢。 - user3576868
你解决了这个问题吗? - user3188912
3个回答

9
当服务器程序尝试在端口53705上打开套接字以进行侦听时,您会收到错误。"Address already in use"消息意味着另一个进程正在使用端口53705,可能是某个守护进程巧合地打开了相同的端口,或者您的网络浏览器已经打开了此端口并仍在使用它。
然而,最有可能的是您在后台运行了另一个服务器程序实例。请检查所有终端窗口或检查IDE中包含运行程序状态的标签页。
顺便说一句,“unique port”有点误导人,因为端口53705没有任何“独特”的方式,只是您(或其他人)选择了希望未被使用的端口号。要获取真正的唯一端口,请使用“new ServerSocket(0)”,该方法将请求系统分配一个未使用的端口。要查找分配的端口,请使用“serverSocket.getLocalPort()”。您可以将其打印出来,然后作为命令行选项传递给客户端程序。

1
我认为你遇到了平台和Java库特定的问题。请提供有关您的操作系统平台(x86 / x64)以及您正在使用哪个供应商的JDK版本的附加信息?
根据此链接 {{link1:http://www.oracle.com/technetwork/java/javase/7u51-relnotes-2085002.html}} 在Oracle JDK 7u51以上:分配给所有代码(包括不受信任的代码)的默认套接字权限已更改。您只能将套接字绑定到每个系统上的短暂端口范围内。 端口 53705 应该是一个安全的临时端口。 但仍然使用
netstat -an | grep 53705 

要确认端口在Linux中是否被使用,可以使用netstat命令;在Windows中,可以使用tcpview。您可以使用以下命令:

less /proc/sys/net/ipv4/ip_local_port_range

如果您想在Linux系统上检查短暂端口范围并找到

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

在Windows中确定您的短暂端口范围。有关Windows中短暂范围的更多信息,请参见如何更改/查看Windows机器中的短暂端口范围

我可以确认您的服务器代码和客户端(无“man”->“main”拼写错误)在Opensuse 12.3上运行。

Java version "1.7.0_51"
OpenJDK Runtime Environment (IcedTea 2.4.4) (suse-8.32.5-i386)
OpenJDK Client VM (build 24.45-b08, mixed mode)
jvm is running by an non admin user with groups: www,dialout,video,shadow,users

这将导致安全异常,而不是BindException。你也引用了错误的发布说明。它们说“仍然有可能将套接字绑定到短暂端口范围...”-1。 - user207421
@EJP:感谢您的评论,但新的限制是,在临时范围之外绑定套接字现在需要系统安全策略中的显式权限,这意味着它是我的编程环境设置之外的附加设置。如果我没有这样做,我仍然无法绑定端口,我是否也会因安全异常而导致BindException?还是我错了?谢谢。 - Yingding Wang

0

我测试了你的代码,它能正常工作(意思是:我可以连接到服务器,但未测试其他部分)。只需注意MessageSendClient中的主方法,有一个拼写错误("man"而不是"main"),正确的签名应为:

public static void main(String[] args)

不是

public static void main(String args[]) // Still compatible but not recommended (C-like syntax)

请执行以下命令,确保监听端口没有被占用(将YOUR_PORT替换为实际端口号)

netstat -tulpn | grep :YOUR_PORT

这就是你得到那个异常的原因。如果你在Windows上,你可以直接运行

netstat -an

并搜索端口。


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