Java网络编程核心技术详解(视频微课版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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节(设定连接时间、延迟和带宽的相对重要性)。