socket.setReuseAddress(true); 含义
设置Socket的选项
参考URL:
如下代码, sock.setReuseAddress(true);什么含义?
public static Socket getSocket(InetSocketAddress addr) throws IOException {
Socket sock = new Socket();
sock.setReuseAddress(true);
sock.setSoTimeout(ClientGlobal.g_network_timeout);
sock.connect(addr, ClientGlobal.g_connect_timeout);
return sock;
}
在网络应用中(如Java Socket Server),当服务关掉立马重启时,很多时候会提示端口仍被占用(因端口上有处于TIME_WAIT的连接)。此时可通过 SO_REUSEADDR 参数( socket.setReuseAddress(true); )来使得服务关掉重启时立马可使用该端口,而不是提示端口占用。
如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用 端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息, 抛出“Address already in use: JVM_Bind”。如果你的服务程序停止后想立即重启,不等60秒,而新套接字依旧 使用同一端口,此时 SO_REUSEADDR 选项非常有用。
TCP关闭过程中的TIME_WAIT状态就是client端的2MSL状态,其作用是确保server端可以收到client端发送的确认报文:最后一个确认报文可能没被server端收到,此时server端会重发fin报文,client端等待2MSL时间使得可以收到server端重发的fin报文。
SO_RESUSEADDR选项:
- 设置该选项:public void setResuseAddress(boolean on)throws SocketException
- 读取该选项 public void getResuseAddress(boolean on)throws SocketException
当接受方通过Socket的close()方法关闭Socket时,如果网络上还有发送到这个Socket的数据,那么底层的Socket不会立刻释放本地端口,而是会等待一段时间,确保收到了网络上发送过来的延迟数据,然再释放该端口。Socket接受到延迟数据后,不会对这些数据做任何处理。Socket接受延迟数据的目的是,确保这些数据不会被其他碰巧绑定到同样端口的新进程接收到。
客户程序一般采用随机端口,因此会出现两个客户端程序绑定到同样端口的可能性不大。许多服务器都使用固定的端口。当服务器进程关闭后,有可能它的端口还会被占用一段时间,如果此时立刻在同一主机上重启服务器程序,由于端口已经被占用,使得服务器无法绑定到该端口,启动失败。为了确保一个进程被关闭后,及时它还没有释放该端口,同一个主机上的其他进程还可以立刻重用该端口,可以调用Socket的setResuseAddress(true)方法:
值得注意的是:socket.setResuseAddress(true)方法必须在Socket还没有绑定到一个本地端口之前调用,否则执行socket.setResuseAddress(true)方法无效
因此必须按照以下方法创建Socket对象,然后在连接远程服务器:
此外,两个共用同一个端口的进程必须都调用socket.setReuseAddress(true)放方法才能使得一个进程关闭Socket后,另一个进程的Socket能够立刻重用相同的端口。