文章目录
- 1. 构造服务器Socket
- 2. 构造但不绑定端口
- 3. 获得服务器Socket的有关信息
- 4. Socket选项
- 5. SO_TIMEOUT
- 6. SO_REUSEADDR
- 7. SO_RCVBUF
- 8. 服务类型
1. 构造服务器Socket
有四个公共的ServerSocket构造函数
public ServerSocket(int port) throws BindException, IOException
public ServerSocket(int port, int queueLength) throws BindException,IOException
public ServerSocket(int port,int queueLength,InetAddress bindAddress) throws IOException
public ServerSocket() throws IOException
这些构造函数可以指定端口了、保存入站连接请求所用的队列的长度,以及要绑定的本地网络接口。它们所做的工作几乎是一样的,只是有些方法会使用队列长度和绑定地址的默认值。如果试图将队列长度设置为大于操作系统的最大队列长度,则会使用最大队列长度。默认地,如果不指定绑定的地址,且一个主机有多个网络接口和IP地址,服务器Socket会在所有接口和IP地址的指定端口上监听。如果指定本地IP地址,就会绑定这个IP地址。如果这三个构造函数的端口传入0,则操作系统会帮你选择端口 。
下面的代码的作用是查找可用的本地端口(哪些端口不可用)
public static void main(String[] args) {
for (int i = 1; i <= 65535; i++) {
try{
ServerSocket serverSocket=new ServerSocket(i);
}catch (IOException e){
System.out.println("There is a server on port:"+i+".");
}
}
}
2. 构造但不绑定端口
无参数构造函数会创建一个ServerSocket对象,但未将它具体绑定到某个端口,所以初始时它不能接受任何连接。以后可以用bind来进行绑定。
public void bind(SocketAddress endpoint) throws IOException
public void bind(SocketAddress endpoint, int ququeLength) throws IOException
这个特性的主要用途是,允许程序在绑定端口之前设置服务器socket选项,有些选项在服务器socket绑定后必须固定,一般模式如下:
ServerSocket ss=new ServerSocket();
SocketAddress http=new InetSocketAddress(80);
ss.bind(http);
也可以为SocketAddress传入null来选择任意端口,这与其他构造函数中为端口传入0的作用相似。
3. 获得服务器Socket的有关信息
ServerSocket类提供了两个获取方法,可以指出这个服务器Socket占用的本地地址和端口。
//返回服务器(本地主机)使用的地址
public InetAddress getInetAddress()
//返回服务器(本地主机)监听的端口
public int getLocalPort()
public static void main(String[] args) {
try{
ServerSocket server=new ServerSocket(0);
System.out.println("This server runs on port "+server.getLocalPort());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
如果ServerSocket没有绑定到某个端口,则getLocalport()返回返回-1,与大多数Java对象一样,还可以使用toString()方法打印一个ServerSocket。
4. Socket选项
Socket选项指定了ServerSocket类所依赖的原生Socket如果发送和接受数据。对于服务器Socket,Java支持以下3个选项。
- SO_TIMEOUT
- SO_REUSEADDR
- SO_RCVBUF
另外还允许你为Socket的数据包设置性能首选项。
5. SO_TIMEOUT
该选项是accept()在抛出java.io.InterruptedIOException异常前等待入站连接的时间,以毫秒算。如果该选项设置为0,accept就永远不会超时。这个默认值的作用就是永不超时。如果你想操作这个字段,可以使用到下面的函数:
public void setSoTimeout(int timeout)throws SocketException
public int getSoTimeout()throws IOException
调用accept函数时开始计时,如果超时会抛出一个SocketTimeoutException,这个IOException的子类。
6. SO_REUSEADDR
服务器Socket的SO_REUSEADDR选项与客户端Socket的SO_REUSEADDR选项非常类似。它确定了是否允许一个新的Socket绑定到之前使用过的一个端口,而此时可能还有一些发送到原Socket的数据正在网络上传输。有两个方法可以分别获取和设置这个选项;
public boolean getReuseAddress() throws SocketException
public void setReuseAddress(boolean on)throws SocketException
7. SO_RCVBUF
该选项设置了服务器Socket接受的客户端Socket默认接受缓存区的大小。这个缓存区可以由以下两个方法读/写:
public int getReceiveBufferSize() throws SocketException
public void setReceiveBufferSize(int size) throws SocketException
设置一个服务器的SO_RCVBUF就像在accept()返回的各个Socket上调用setReceiveBufferSize()。这个选项为流中各个IP数据包的大小给出一个建议值。更快的连接可能希望使用更大的缓冲区,不过大多数情况下默认值就足够了。可以在绑定服务器Socket之前或之后设置这个选项,除非你想设置一个大于64KB的接收缓冲区大小。在这种情况下,必须在绑定之前,为未绑定的ServerSocket设置这个选项。
8. 服务类型
不同的Internet服务类型有不同的性能要求。例如,体育运动的直播视频要相对较高的的带宽,另一方面,电影可能仍需要高带宽,但可以接受较大的延迟。TCP定义了4个通用业余流类型:
- 低成本
- 高可靠性
- 最大吞吐量
- 最小延迟
可以为一个给定的Socket请求这些业务流类型。例如可以请求低成本时可用的最小延迟。这些度量都是模糊的,而且是相对的,不能作为服务保证,并不是所有路由器和原生TCP栈都支持这些业务流类型。对于服务器所接受的Socket,setPerformancePreferences()
方法描述了为其连接时间、延迟和带宽给定的优先级:
public void setPerformancePreferences(int connectionTime, int latency,int bandwidth)
例如,通过将connectionTime设置为2,latency设置为1,bandwidth设置为3,这表示最大带宽是最重要的特性,最小延迟最不重要,连接时间居中:
socket.setPerformancePreferences(2,1,3)
至于给定的VM究竟如何实现,则取决于具体的Socket实现,底层Socket实现不要求考虑这些需求。它们只是为TCP栈提供了所需策略的一个提示。很多实现会完全忽略这些值。