2.3 Nagle算法的问题
  在传输大文件的时候,如果使用这个算法,那么会出现明显的延迟现象,因此,在这种情况下,好是关闭这个算法。
  知道了Nagle算法,知道了TCP_NODELAY这个参数的意义了,如果这个参数被设置为True,那么是关闭Nagle算法,实现无延迟传输,如果设置为false,则是打开这个算法,会对发送的数据进行缓存。
  3、public final static int SO_BINDADDR = 0x000F;
  获取绑定套接字的本地地址(不能仅将此选项“设置”为“得到”,因为套接字是在创建时绑定的,所以本地绑定的地址不可更改)。
  4、public final static int SO_REUSEADDR = 0x04;
  这个参数表示套接字对端口是否可重用。
  这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息,指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时 SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不可能。
  一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组还是确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使用 SO_REUSEADDR 选项。
  5、public final static int SO_BROADCAST = 0x0020;
  这个参数选项用来控制广播,目前只有在DatagramSocket里支持。
  6、public final static int IP_MULTICAST_IF = 0x10;
  用来控制多播的参数选项,目前只有在MulticastSocket里支持
  在MulticastSocket的源代码里有设置多播的方法:
  public void setInterface(InetAddress inf) throws SocketException {
  if (isClosed()) {
  throw new SocketException("Socket is closed");
  }
  checkAddress(inf, "setInterface");
  synchronized (infLock) {
  getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
  infAddress = inf;
  }
  }
  7、public final static int IP_MULTICAST_IF2 = 0x1f;
  这个字段的效果和上面的是一样的,只是扩展支持IPV6
  8、public final static int IP_MULTICAST_LOOP = 0x12;
  用来设置本地回环接口的多播特性,在MulticastSocket源代码中有相关方法:
/**
* Disable/Enable local loopback of multicast datagrams
* The option is used by the platform's networking code as a hint
* for setting whether multicast data will be looped back to
* the local socket.
*
* <p>Because this option is a hint, applications that want to
* verify what loopback mode is set to should call
* {@link #getLoopbackMode()}
* @param disable <code>true</code> to disable the LoopbackMode
* @throws SocketException if an error occurs while setting the value
* @since 1.4
* @see #getLoopbackMode
*/
public void setLoopbackMode(boolean disable) throws SocketException {
getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
}
  9、public final static int IP_TOS = 0x3;
  这个参数是用来控制IP头中的TOS字段的,是用来控制和优化IP包的路径的,在Socket源代码里有一个设置的方法:
/**
* Sets traffic class or type-of-service octet in the IP
* header for packets sent from this Socket.
* As the underlying network implementation may ignore this
* value applications should consider it a hint.
*
* <P> The tc <B>must</B> be in the range <code> 0 <= tc <=
* 255</code> or an IllegalArgumentException will be thrown.
* <p>Notes:
* <p> For Internet Protocol v4 the value consists of an octet
* with precedence and TOS fields as detailed in RFC 1349. The
* TOS field is bitset created by bitwise-or'ing values such
* the following :-
* <p>
* <UL>
* <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
* <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
* <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
* <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
* </UL>
* The last low order bit is always ignored as this
* corresponds to the MBZ (must be zero) bit.
* <p>
* Setting bits in the precedence field may result in a
* SocketException indicating that the operation is not
* permitted.
* <p>
* As RFC 1122 section 4.2.4.2 indicates, a compliant TCP
* implementation should, but is not required to, let application
* change the TOS field during the lifetime of a connection.
* So whether the type-of-service field can be changed after the
* TCP connection has been established depends on the implementation
* in the underlying platform. Applications should not assume that
* they can change the TOS field after the connection.
* <p>
* For Internet Protocol v6 <code>tc</code> is the value that
* would be placed into the sin6_flowinfo field of the IP header.
*
* @param tc        an <code>int</code> value for the bitset.
* @throws SocketException if there is an error setting the
* traffic class or type-of-service
* @since 1.4
* @see #getTrafficClass
*/
public void setTrafficClass(int tc) throws SocketException {
if (tc < 0 || tc > 255)
throw new IllegalArgumentException("tc is not in range 0 -- 255");
if (isClosed())
throw new SocketException("Socket is closed");
getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
}
  从源代码的注释看,TOS设置了是否生效,和底层的操作系统的实现有关。应用程序无法保证TOS的变更会对socket连接产生影响。个人认为,TOS在一般情况下用不到。
  10、public final static int SO_LINGER = 0x0080;
  先看Socket源代码:
/**
* Enable/disable SO_LINGER with the specified linger time in seconds.
* The maximum timeout value is platform specific.
*
* The setting only affects socket close.
*
* @param on     whether or not to linger on.
* @param linger how long to linger for, if on is true.
* @exception SocketException if there is an error
* in the underlying protocol, such as a TCP error.
* @exception IllegalArgumentException if the linger value is negative.
* @since JDK1.1
* @see #getSoLinger()
*/
public void setSoLinger(boolean on, int linger) throws SocketException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!on) {
getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on));
} else {
if (linger < 0) {
throw new IllegalArgumentException("invalid value for SO_LINGER");
}
if (linger > 65535)
linger = 65535;
getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
}
}
  这个字段对Socket的close方法产生影响,当这个字段设置为false时,close会立即执行并返回,如果这时仍然有未被送出的数据包,那么这些数据包将被丢弃。如果设置为True时,有一个延迟时间可以设置。这个延迟时间是close真正执行所有等待的时间,大为65535。