控制默认行为
TCP/IP协议的开发者用了大量的时间来考虑协议的默认行为,以满足大部分应用程序的需要。(如果你对此表示怀疑,可以参考RFC1122和1123,它们根据多年的经验对TCP/IP协议的实现的推荐行为进行了详尽的描述。)对于大多数应用程序来说,这些设计都非常适合,然而,"满足所有需求的一种尺寸"能够真正适用于所有场合的情况非常少。前面我们已经看到UDP回显客户端的例子。默认情况下,DatagramSocket类的receive()方法将无限期地阻塞等待一个数据报文,在我们的例子中,通过在UDP套接字上指定了一个接收超时时间并在TimeLimitEchoProtocol类中使用了setSoTimeout()进行设置,从而改变了协议的默认行为。
1 Keep-Alive
如果一段时间内没有数据交换,通信的每个终端可能都会怀疑对方是否还处于活跃状态。TCP协议提供了一种keep-alive的机制,该机制在经过一段不活动时间后,将向另一个终端发送一个探测消息。如果另一个终端还出于活跃状态,它将回复一个确认消息。如果经过几次尝试后依然没有收到另一终端的确认消息,则终止发送探测信息,关闭套接字,并在下一次尝试I/O操作时抛出一个异常。注意,应用程序只要在探测信息失败时才能察觉到keep-alive机制的工作。
Socket: 保持活跃
boolean getKeepAlive()
void setKeepAlive(boolean on)
默认情况下,keep-alive机制是关闭的。通过调用setKeepAlive()方法将其设置为true来开启keep-alive机制。
2发送和接收缓存区的大小
一旦创建了一个Socket或DatagramSocket实例,操作系统就必须为其分配缓存区以存放接收的和要发送的数据。(我们将在第6.1节对其进行更详细的介绍)
Socket, DatagramSocket: 设置和获取发送接收缓存区大小
int getReceiveBufferSize()
void setReceiveBufferSize(int size)
int getSendBufferSize()
void setSendBufferSize(int size)
getReceiveBufferSize(),setReceiveBufferSize(),getSendBufferSize(),和setSendBufferSize()
方法分别用于获取和设置接收发送缓冲区的大小(以字节为单位)。需要注意的是,这里指定的大小只是作为一种建议给出的,实际大小可能与之存在差异。
还可以在ServerSocket上指定接收缓冲区大小。不过,这实际上是为accept()方法所创建的新Socket实例设置接收缓冲区大小。为什么可以只设置接收缓冲区大小而不设置发送缓冲区的大小呢?当接收了一个新的Socket,它就可以立刻开始接收数据,因此需要在accept()方法完成连接之前设置好缓冲区的大小。另一方面,由于可以控制什么时候在新接受的套接字上发送数据,因此在发送之前还有时间设置发送缓冲区的大小。
ServerSocket: 设置/获取所接受套接字的接收缓冲区大小
int getReceiveBufferSize()
void setReceiveBufferSize(int size)
getReceiveBufferSize()和setReceiveBufferSize()方法用于获取和设置由accept()方法创建
的Socket实例的接收缓冲区的大小(字节)。
3超时
如前面所介绍的,很多I/O操作如果不能立即完成就会阻塞等待:读操作将阻塞等待直到至少有一个字节可读;接收操作将阻塞等待直到成功建立连接。不幸的是阻塞的时间没限制。可以为各种操作指定一个最大阻塞时间。
Socket, ServerSocket, DatagramSocket: 设置/获取I/O超时时间
int getSoTimeout()
void setSoTimeout(int timeout)
getSoTimeout()和setSoTimeout()方法分别用于获取和设置读/接收数据操作以及accept操作的最长阻塞时间。超时设置为0表示该操作永不超时。如果阻塞超过了超时时长,则抛出一个异常。
4地址重用
在某些情况下,可能希望能够将多个套接字绑定到同一个套接字地址。对于UDP多播的情况,在同一个主机上可能有多个应用程序加入了相同的多播组。对于TCP,当一个连接关闭后,通信的一端(或两端)必须在"Time-Wait"状态上等待一段时间,以对传输途中丢失的数据包进行清理(见第6.4.2节)。不幸的是,通信终端可能无法等到Time-Wait结束。对于这两种情况,都需要能够与正在使用的地址进行绑定的能力,这就要求实现地址重用。
Socket, ServerSocket, DatagramSocket: 设置/获取地址重用
boolean getReuseAddress()
void setReuseAddress(boolean on)
getReuseAddress()和setReuseAddress()方法用于获取和设置地址重用许可。设置为true表示启用了地址重用功能。
5消除缓冲延迟
TCP协议将数据缓存起来直到足够多时一次发送,以避免发送过小的数据包而浪费网络资源。虽然这个功能有利于网络,但应用程序可能对所造成的缓冲延迟不能容忍。好在可以人为禁用缓存功能。
Socket: 设置/获取TCP缓冲延迟
boolean getTcpNoDelay()
void setTcpNoDelay(boolean on)
getTcpNoDelay()和setTcpNoDelay()方法用于获取和设置是否消除缓冲延迟。将值设置
为true表示禁用缓冲延迟功能。
6紧急数据
假设你已经向一个慢速接收者发送了很多数据,突然又有了它急需的其它数据。如果将这些数据发送到输出流,它们将追加在常规数据队列的后面,无法保证接收者能够立即接收。为了解决这个问题,TCP协议中包含了紧急(urgent)数据的概念,这类数据可以(理论上来说)跳到前面去。由于它们能够绕过常规数据流,这些数据称为频道外数据。
Socket: 紧急数据
void sendUrgentData(int data)
boolean getOOBInline()
void setOOBInline(boolean on)
要发送紧急数据需要调用sendUrgentData() 方法,它将发送其int参数的最低位字节。要接收这个字节,必须为setOOBInline()方法传递true参数启用接收者对频道外数据的接收。该字节在接收者的输入流中被接收。发送于紧急字节之前的数据将处于接收者的输入流中的紧急字节前面。如果没有启用接收者接收频道外数据的功能,紧急字节将被无声地丢弃。
注意Java中的紧急数据几乎没什么用,因为紧急字节与常规字节按照传输的顺序混在了一起。实际上,Java接收者并不能区分其是否在接收紧急数据。
7关闭后停留
当调用套接字的close()方法后,即使套接字的缓冲区中还有没有发送的数据,它也将立即返回。这样不发送完所有数据可能导致的问题是主机将在后面的某个时刻发生故障。其实可以选择让close()方法"停留"或阻塞一段时间,直到所有数据都已经发送并确认,或发生了超时。详情见第6.4.2节
Socket: 在close()方法停留
int getSoLinger()
void setSoLinger(boolean on, int linger)
如果调用setSoLinger()并将其设置为true,那么后面再调用的close()方法将阻塞等待,直到远程终端对所有数据都返回了确认信息,或者发生了指定的超时(秒)。如果发生了超时,TCP连接将强行关闭。如果开启了停留功能,getSoLinger()方法将返回指定的超时时间,否则返回-1。
8广播许可
一些操作系统要求显示地对广播许可进行请求。你可以对广播许可进行控制。正如前面所介绍的,DatagramSockets类提供了广播服务功能。
DatagramSocket:设置/获取广播许可
boolean getBroadcast()
void setBroadcast(boolean on)
getBroadcast()和setBroadcast()方法分别用于获取和设置广播许可。设置为true表示允许广播。在Java中,默认情况下是允许进行广播的。
9通信等级
有的网络对满足服务条件的数据包提供了增强的服务或"额外的保险"。一个数据包的通信等级(traffic class)由数据包在网络中传输时其内部的一个值来指定。例如,有的网络会为"黄金服务"等级的数据包提供较高的优先级,以减少其传输延迟和丢包的概率。有的网络可能会根据指定的通信等级为数据包选择路由。不过需要注意的是,网络的提供者对这类服务要收取额外的费用,因此不能保证这些选项实际上是否生效。
Socket, DatagramSocket: 设置/获取通信等级
int getTrafficClass()
void setTrafficClass(int tc)
通信等级通常由一个整数或一组位标记指定。位标记的数量和意义则取决于所使用的IP协议版本。
10 基于性能的协议选择
TCP协议并不是套接字惟一可选的协议。使用什么样的协议取决于应用程序的侧重点在是什么。 Java允许开发者根据不同性能特征对于应用程序的重要程度,为具体实现给出"建议"。底层的网络系统可能会根据这些建议,在一组能够提供同等的数据流服务,同时又具有不同的性能特征的不同协议中做出选择。
Socket, ServerSocket: 指定协议参数选择
void setPerformancePreferences(int
connectionTime, int latency, int bandwidth)
套接字的性能参数由三个整数表示,分别代表连接时间,延迟和带宽。具体的数值并不重要,Java 将比较各种标准的相关参数值,并返回与之最匹配的可用协议。例如,如果connectionTime和latency都等于0,bandwidth等于1,那么则将选择能够使带宽最大的协议。注意,要使这个方法生效,必须在套接字建立连接之前调用。
相关下载:
Java_TCPIP_Socket编程(doc)
文献来源:
UNDONER(小杰博客) :
LSOFT.CN(琅软中国) :