java.net.BindException 处理

本文通过分析ServerSocket的创建及监听过程,解决了由于频繁新建ServerSocket实例而导致的端口冲突问题,并介绍了如何利用setReuseAddress方法避免端口冲突。
07-15 19:59:00.011: W/System.err(2334): java.net.BindException: bind failed: EADDRINUSE (Address already in use)
07-15 19:59:00.015: W/System.err(2334): at libcore.io.IoBridge.bind(IoBridge.java:89)
07-15 19:59:00.019: W/System.err(2334): at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:150)
07-15 19:59:00.019: W/System.err(2334): at java.net.ServerSocket.<init>(ServerSocket.java:100)
07-15 19:59:00.019: W/System.err(2334): at java.net.ServerSocket.<init>(ServerSocket.java:69)
07-15 19:59:00.019: W/System.err(2334): at com.casit.controlapp.service.ControlService$TcpReceiveThread.run(ControlService.java:96)
07-15 19:59:00.023: W/System.err(2334): at java.lang.Thread.run(Thread.java:856)
07-15 19:59:00.027: W/System.err(2334): Caused by: java.net.BindException: bind failed: EADDRINUSE (Address already in use)
07-15 19:59:00.027: W/System.err(2334): at libcore.io.IoBridge.bind(IoBridge.java:89)
07-15 19:59:00.027: W/System.err(2334): at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:150)
07-15 19:59:00.027: W/System.err(2334): at java.net.ServerSocket.<init>(ServerSocket.java:100)
07-15 19:59:00.027: W/System.err(2334): at java.net.ServerSocket.<init>(ServerSocket.java:69)
07-15 19:59:00.027: W/System.err(2334): at com.casit.controlapp.service.ControlService$TcpReceiveThread.run(ControlService.java:96)
07-15 19:59:00.027: W/System.err(2334): at java.lang.Thread.run(Thread.java:856)
07-15 19:59:00.027: W/System.err(2334): Caused by: libcore.io.ErrnoException: bind failed: EADDRINUSE (Address already in use)
07-15 19:59:00.027: W/System.err(2334): at libcore.io.Posix.bind(Native Method)
07-15 19:59:00.027: W/System.err(2334): at libcore.io.ForwardingOs.bind(ForwardingOs.java:39)
07-15 19:59:00.027: W/System.err(2334): at libcore.io.IoBridge.bind(IoBridge.java:87)
07-15 19:59:00.027: W/System.err(2334): ... 5 more
07-15 19:59:00.031: W/System.err(2334): libcore.io.ErrnoException: bind failed: EADDRINUSE (Address already in use)
07-15 19:59:00.031: W/System.err(2334): at libcore.io.Posix.bind(Native Method)
07-15 19:59:00.031: W/System.err(2334): at libcore.io.ForwardingOs.bind(ForwardingOs.java:39)
07-15 19:59:00.031: W/System.err(2334): at libcore.io.IoBridge.bind(IoBridge.java:87)

07-15 19:59:00.035: W/System.err(2334): ... 5 more

     在编写socket通信时出现了上述的log信息,在log信息中的两端蓝色字体中,强调了 java.net.BindException的异常,原因bind failed: EADDRINUSE (Address already in use)

查找资料,在《Unix-网络编程 卷1:套接字联网API》一书中有对 TIME_WAIT状态,bind()函数的讲解,再联系我当时写的程序:

ServerSocket stopServerSocket;

Socket stopSocket;

while(true){

  try{

      stopServerSocket = new ServerSocket(45000);

      stopSocket = stopServerSocket.accept();

}catch(IOException e){

      e.printStackTrace();

}

}

我在server端不停建立new新的ServerSocket,这就导致了地址冲突。

我仔细一分析,发现我写的代码有问题,我需要做的是在服务器的45000端口监听socket,而并不需要每次都new一个新的ServerSocket,于是我将代码改为如下:

ServerSocket stopServerSocket;

Socket stopSocket;

     topServerSocket = new ServerSocket(45000);

while(true){ 

try{ 

     stopSocket =stopServerSocket.accept();

}catch(IOException e){ 

     e.printStackTrace();

}}

在修改之后,程序运行没有问题,但是我在看了一些资料后在原来的程序中加入了:

setReuseAddress(boolean on)方法

Enable/disable the SO_REUSEADDR socketoption.

这个方法主要是使能SO_REUSEADDR,对于这个变量的解释在  http://developerweb.net/viewtopic.php?id=3019,代码如下:

while(true){

   try {                             

        if(stopServerSocket == null){

             stopServerSocket = new ServerSocket();

             stopServerSocket.setReuseAddress(true);

             stopServerSocket.bind(newInetSocketAddress(40000));

        }                                          

         stopSocket= stopServerSocket.accept();

   }catch(IOException e){

         e.printStackTrace();

}

    上面的方法中,相当于就是我建立许多的ServerSocket,但是它们都是使用同一个45000端口,因为有setReuseAddress(true)这个方法就是的同一个端口可以被多个socket使用,不会出现 (Address already in use)的问题

   更多的资料可以参考:http://blog.youkuaiyun.com/liusujian02/article/details/1944520

                                                    http://www.360doc.com/content/11/0820/09/4602013_141864815.shtml




  




    




    




    




    




    



  
                
<think>我们正在处理一个Java网络异常:java.net.BindException: Cannot assign requested address 这个异常通常发生在尝试绑定一个本地网络地址(IP和端口)时,系统无法分配该地址。常见原因包括: 1. 端口已被占用:另一个进程已经绑定了相同的端口。 2. 使用了一个无效的IP地址:例如,尝试绑定一个不属于本机的IP地址。 3. 临时端口耗尽:在高并发场景下,短时间内创建大量连接导致端口资源耗尽。 4. 绑定到非本地IP:比如试图绑定一个外部IP,而该IP并未配置在本地网络接口上。 解决方法: 1. 检查端口占用:使用命令(如Linux的`netstat -tulnp | grep <端口号>`)查看端口是否被占用,并终止占用进程或更换端口。 2. 确认IP地址有效性:确保绑定的IP地址是本地配置的地址(如127.0.0.1或本机局域网IP),使用`ifconfig`(Linux)或`ipconfig`(Windows)查看。 3. 调整临时端口范围:对于端口耗尽问题,可以扩大临时端口范围(Linux:`sysctl`修改`net.ipv4.ip_local_port_range`)。 4. 使用通配符地址:如果需要绑定所有可用地址,可以使用0.0.0.0(IPv4)或::(IPv6)。 示例代码中绑定端口的正确方式: 在Java中,绑定服务器套接字时,使用0.0.0.0表示绑定所有本地地址: ```java ServerSocket serverSocket = new ServerSocket(8080, 0, InetAddress.getByName("0.0.0.0")); ``` 但是,如果异常是由于端口耗尽,则需要优化连接管理(如重用端口)或增加可用端口范围。 注意:在Linux中,端口耗尽还可能因为TIME_WAIT状态导致,可以通过调整内核参数(如`net.ipv4.tcp_tw_reuse`)缓解。 §§相关问题§§ 1. 如何在Linux中检查特定端口是否被占用? 2. 如何解决因TIME_WAIT状态过多导致的端口资源不足? 3.Java中如何设置SO_REUSEADDR以允许端口重用? 4. 如何配置Linux系统的临时端口范围? 5. 为什么绑定0.0.0.0和127.0.0.1有区别? </think>当在 Java 应用程序中出现 `java.net.BindException: Cannot assign requested address` 错误时,这表示系统无法将请求的网络地址绑定到套接字。以下是关键原因和解决方案: ### **常见原因** 1. **端口冲突** - 目标端口已被其他进程占用(常见于 `8080`、`80` 等高频端口) - 查看占用命令:`netstat -tuln | grep <端口号>` 2. **IP 地址无效** - 尝试绑定不存在的本地 IP(如 `192.168.99.99`) - 检查可用 IP:`ip addr`(Linux)或 `ipconfig`(Windows) 3. **临时端口耗尽** - 高并发场景下,可用临时端口(`32768-61000`)被快速消耗 - 验证当前范围:`sysctl net.ipv4.ip_local_port_range` 4. **TIME_WAIT 状态累积** - TCP 连接关闭后保持 `TIME_WAIT` 状态(默认 60 秒),占用端口资源 --- ### **解决方法** #### **1. 端口冲突处理** ```bash # 查找占用进程并终止 sudo lsof -i :8080 # 列出进程 kill -9 <PID> # 强制终止 ``` #### **2. 正确绑定 IP** ```java // 优先使用通配符地址 0.0.0.0(绑定所有可用 IP) ServerSocket server = new ServerSocket(8080, 0, InetAddress.getByName("0.0.0.0")); ``` #### **3. 临时端口扩展** ```bash # 扩大临时端口范围(Linux) sudo sysctl -w net.ipv4.ip_local_port_range="10240 65000" ``` #### **4. 优化 TIME_WAIT** ```bash # 启用快速回收和重用(Linux) sudo sysctl -w net.ipv4.tcp_tw_reuse=1 sudo sysctl -w net.ipv4.tcp_tw_recycle=1 # 注意:内核 4.12+ 已移除 ``` #### **5. 代码级修复** ```java // 设置 SO_REUSEADDR 允许端口复用 ServerSocket server = new ServerSocket(); server.setReuseAddress(true); // ★ 关键步骤 server.bind(new InetSocketAddress(8080)); ``` --- ### **高级排查** - **网络配置检查** ```bash ip route show # 验证路由表 firewall-cmd --list-ports # 检查防火墙 ``` - **连接跟踪监控** ```bash conntrack -L # 查看活动连接 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值