java so reuseaddr_Socket 选项之 SO_REUSEADDR

前面介绍到四次挥手的时候有讲到,主动断开连接的那一端需要等待 2 个 MSL 才能最终释放这个连接。一般而言,主动断开连接的都是客户端,如果是服务端程序重启或者出现 bug 崩溃,这时服务端会主动断开连接,如下图所示

677b24f9d844331a654bfa2f5d0f8534.png

因为要等待 2 个 MSL 才能最终释放连接,所以如果这个时候程序马上启动,就会出现Address already in use错误。要过 1 分钟以后才可以启动成功。如果你写了一个 web 服务器,崩溃以后被脚本自动拉起失败,需要等一分钟才正常,运维可能要骂娘了。

下面来写一段简单的代码演示这个场景是如何产生的。

public class ReuseAddress {

public static void main(String[] args) throws IOException {

ServerSocket serverSocket = new ServerSocket();

// setReuseAddress 必须在 bind 函数调用之前执行

serverSocket.setReuseAddress(false);

serverSocket.bind(new InetSocketAddress(8080));

System.out.println("reuse address: " + serverSocket.getReuseAddress());

while (true) {

Socket socket = serverSocket.accept();

System.out.println("incoming socket..");

OutputStream out = socket.getOutputStream();

out.write("Hello\n".getBytes());

out.close();

}

}

}

这段代码的功能是启动一个 TCP 服务器,客户端连上来就返回了一个 "Hello\n" 回去。

使用 javac 编译 class 文件javac ReuseAddress.java;,然后用 java 命令运行java -cp . ReuseAddress。使用 nc 命令连接 8080 端口nc localhost 8080,应该会马上收到服务端返回的"Hello\n"字符串。现在 kill 这个进程,马上重启这个程序就可以看到程序启动失败,报 socket bind 失败,堆栈如下:

Exception in thread "main" java.net.BindException: 地址已在使用 (Bind failed)

at java.net.PlainSocketImpl.socketBind(Native Method)

at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)

at java.net.ServerSocket.bind(ServerSocket.java:375)

at java.net.ServerSocket.bind(ServerSocket.java:329)

at ReuseAddress.main(ReuseAddress.java:18)

将代码修改为serverSocket.setReuseAddress(false);,再次重复上面的测试过程,再也不会出现上述异常了。

0x02 为什么需要 SO_REUSEADDR 参数

服务端主动断开连接以后,需要等 2 个 MSL 以后才最终释放这个连接,重启以后要绑定同一个端口,默认情况下,操作系统的实现都会阻止新的监听套接字绑定到这个端口上。

我们都知道 TCP 连接由四元组唯一确定。形式如下

{local-ip-address:local-port , foreign-ip-address:foreign-port}

一个典型的例子如下图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值