
3.5 ServerSocket选项
ServerSocket有以下3个选项。
·SO_TIMEOUT:表示等待客户连接的超时时间。
·SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。
·SO_RCVBUF:表示接收数据的缓冲区的大小。
3.5.1 SO_TIMEOUT选项
·设置该选项:public void setSoTimeout(int timeout) throws SocketException
·读取该选项:public int getSoTimeout () throws IOException
SO_TIMEOUT表示ServerSocket的accept()方法等待客户连接的超时时间,以ms为单位。如果SO_TIMEOUT的值为0,则表示永远不会超时,这是SO_TIMEOUT的默认值。
当服务器执行ServerSocket的accept()方法时,如果连接请求队列为空,服务器就会一直等待,直到接收到了客户连接才从accept()方法返回。如果设定了超时时间,那么当服务器等待的时间超过了超时时间,就会抛出SocketTimeoutException,它是InterruptedException的子类。
例程3-4的TimeoutTester把超时时间设为6s。
例程3-4 TimeoutTester.java

运行以上程序,6s后,程序会从serverSocket.accept()方法中抛出SocketTimeoutException:

如果把程序中的“serverSocket.setSoTimeout(6000)”注释掉,那么serverSocket.accept()方法永远不会超时,它会一直等待下去,直到接收到了客户的连接,才会从accept()方法返回。
提示
服务器执行serverSocket.accept()方法时,等待客户连接的过程也被称为阻塞。4.1节(线程阻塞的概念)详细介绍了阻塞的概念。
3.5.2 SO_REUSEADDR选项
·设置该选项:public void setResuseAddress(boolean on) throws SocketException
·读取该选项:public boolean getResuseAddress() throws SocketException
这个选项与Socket的SO_REUSEADDR选项相同。本选项用于决定如果网络上仍然有数据向旧的ServerSocket传输,那么是否允许新的ServerSocket绑定到与旧的ServerSocket同样的端口?SO_REUSEADDR选项的默认值与操作系统有关,在某些操作系统中,允许重用端口,而在某些操作系统中则不允许重用端口。
当ServerSocket关闭时,如果网络上还有发送到这个ServerSocket的数据,那么这个ServerSocket不会立刻释放本地端口,而是会等待一段时间,确保接收到了网络上发送过来的延迟数据,然后释放端口。
许多服务器程序都使用固定的端口。当服务器程序关闭后,有可能它的端口还会被占用一段时间,如果此时立刻在同一台主机上重启服务器程序,那么由于端口已经被占用,使得服务器程序无法绑定到该端口,服务器启动失败,并抛出BindException。

为了确保一个进程关闭了ServerSocket后,即使操作系统还没释放端口,同一个主机上的其他进程也可以立刻重用该端口,可以调用ServerSocket的setResuseAddress(true)方法:

值得注意的是,serverSocket.setResuseAddress(true)方法必须在ServerSocket还没有被绑定到一个本地端口时调用,否则执行serverSocket.setResuseAddress(true)方法无效。此外,两个共用同一个端口的进程必须都调用serverSocket.setResuseAddress(true)方法,才能使得一个进程关闭ServerSocket后,另一个进程的ServerSocket能够立刻重用相同端口。
3.5.3 SO_RCVBUF选项
·设置该选项:public void setReceiveBufferSize(int size) throws SocketException
·读取该选项:public int getReceiveBufferSize() throws SocketException
SO_RCVBUF表示服务器端的用于接收数据的缓冲区的大小,以字节为单位。一般说来,传输大的连续的数据块(比如基于HTTP或FTP的数据传输)可以使用较大的缓冲区,这可以减少传输数据的次数,从而提高传输数据的效率。而对于交互式的通信(比如Telnet和网络游戏),则应该采用小的缓冲区,确保能及时把小批量的数据发送给对方。
SO_RCVBUF的默认值与操作系统有关。例如在Window10中运行以下代码时,显示SO_RCVBUF的默认值为65536。

无论是在ServerSocket被绑定到特定端口之前或者之后,调用setReceiveBufferSize()方法都有效。例外情况是如果要设置大于64K的缓冲区,则必须在ServerSocket被绑定到特定端口之前进行设置才有效。例如以下代码把缓冲区的大小设为128K。


执行serverSocket.setReceiveBufferSize()方法,相当于对所有由serverSocket.accept()方法返回的Socket设置接收数据的缓冲区的大小。
3.5.4 设定连接时间、延迟和带宽的相对重要性
·public void setPerformancePreferences(int connectionTime,int latency,int bandwidth)
该方法的作用与Socket的setPerformancePreferences()方法的作用相同,用于设定连接时间、延迟和带宽的相对重要性,参见2.5.10节(设定连接时间、延迟和带宽的相对重要性)。