[Java]Java Socket选项解析

Java里,Socket的Option由java.net.SocketOptions这个接口声明,如下所示:

@Native public final static int TCP_NODELAY = 0x0001;
@Native public final static int SO_BINDADDR = 0x000F;
@Native public final static int SO_REUSEADDR = 0x04;
@Native public final static int SO_BROADCAST = 0x0020;
@Native public final static int IP_MULTICAST_IF = 0x10;
@Native public final static int IP_MULTICAST_IF2 = 0x1f;
@Native public final static int IP_MULTICAST_LOOP = 0x12;
@Native public final static int IP_TOS = 0x3;
@Native public final static int SO_LINGER = 0x0080;
@Native public final static int SO_TIMEOUT = 0x1006;
@Native public final static int SO_SNDBUF = 0x1001;
@Native public final static int SO_RCVBUF = 0x1002;
@Native public final static int SO_KEEPALIVE = 0x0008;
@Native public final static int SO_OOBINLINE = 0x1003;

它们是什么意思呢?下面对每项进行解析。

1. TCP_NODELAY

Disable Nagle’s algorithm for this connection. Written data
to the network is not buffered pending acknowledgement of
previously written data.

纳格算法(Nagle’s algorithm)的工作方式是合并(coalescing)一定数量的输出资料后一次送出。
当某application不断地发送小单位的数据时,tcp会缓存一定量的数据再进行发送。具体算法如下所示:

if there is new data to send
  if the window size >= MSS and available data is >= MSS
    send complete MSS segment now
  else
    if there is unconfirmed data still in the pipe
      enqueue data in the buffer until an acknowledge is received
    else
      send data immediately
    end if
  end if
end if

注:按照算法,是尚未收到前一次ack或未达到指定累积大小前缓存接下来的数据。TCP专用

综上,TCP_NODELAY如果为true,那么数据就不进行缓存(等待上一个ack或达到指定累积大小)。

2. SO_BINDADDR

Fetch the local address binding of a socket (this option cannot
be “set” only “gotten”, since sockets are bound at creation time,
and so the locally bound address cannot be changed). The default local
address of a socket is INADDR_ANY, meaning any local address on a
multi-homed host. A multi-homed host can use this option to accept
connections to only one of its addresses (in the case of a
ServerSocket or DatagramSocket), or to specify its return address
to the peer (for a Socket or DatagramSocket). The parameter of
this option is an InetAddress.

如注释所述,这个Option有如下特点:

  1. 只能通过getOption读取,不能通过setOption设置。因为地址绑定发生在Socket初始化的时候,
    后面就不能更改了。
  2. 默认值为INADDR_ANY。如果用于ServerSocket,即在“multi-homed host(同一主机上有多个网
    络地址)”的情况下,socket接收所有网络接口发过来的数据。设置了指定的Address,那么就接收指定
    接口的数据;如果用于Socket,设置了指定的Address表示向该地址发送数据。
  3. 该选项值的类型为InetAddress

3. SO_REUSEADDR

Sets SO_REUSEADDR for a socket. This is used only for MulticastSockets
in java, and it is set by default for MulticastSockets.

仅用于DatagramSocket(UDP)。一般来说,一个端口释放后会等待两分钟之后才能再被使用,
SO_REUSEADDR是让端口释放后立即就可以被再次使用。

SO_REUSEADDR可以用在以下四种情况下。
(摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启
动程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但
每实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个soc
kt绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的
多播,不用于TCP。

4. SO_BROADCAST

Sets SO_BROADCAST for a socket. This option enables and disables
the ability of the process to send broadcast messages. It is supported
for only datagram sockets and only on networks that support
the concept of a broadcast message (e.g. Ethernet, token ring, etc.),
and it is set by default for DatagramSockets.

SO_BROADCAST决定了socket是否可以发广播。仅用于支持广播的网络。

5. IP_MULTICAST_IF

Set which outgoing interface on which to send multicast packets.
Useful on hosts with multiple network interfaces, where applications
want to use other than the system default. Takes/returns an InetAddress.

用于确定组播(multicast)的网络接口。选项值类型为InetAddress

注:关于单播、广播和组播的概念,可参考http://blog.csdn.net/dabing69221/article/details/17286441

6. IP_MULTICAST_IF

同#IP_MULTICAST_IF,但是可以设IPV4或IPV6地址。

7. IP_MULTICAST_LOOP

This option enables or disables local loopback of multicast datagrams.
This option is enabled by default for Multicast Sockets.

这个选项用于组播。其中“local loopback”的意思是组播包会同时发送给自己(即发送方可以收到自己发出去的数据)。

8. IP_TOS

This option sets the type-of-service or traffic class field
in the IP header for a TCP or UDP socket.

用于设置IP包TOS部分的值。UDP可以在bind之后任意更改设置,TCP在bind前设置。

一般来说,TOS值有以下三种:

 IPTOS_LOWCOST (0x02) 成本优先(?)
 IPTOS_RELIABILITY (0x04) 可靠性优先
 IPTOS_THROUGHPUT (0x08) 吞吐量优先
 IPTOS_LOWDELAY (0x10) 延时优先

9. SO_LINGER

Specify a linger-on-close timeout. This option disables/enables
immediate return from a close() of a TCP Socket. Enabling
this option with a non-zero Integer timeout means that a
close() will block pending the transmission and acknowledgement
of all data written to the peer, at which point the socket is closed
gracefully. Upon reaching the linger timeout, the socket is
closed forcefully, with a TCP RST. Enabling the option with a
timeout of zero does a forceful close immediately. If the specified
timeout value exceeds 65,535 it will be reduced to 65,535.

设置了一个大于0的值给SO_LINGER,表示当关闭这个TCP socket时,如果发送队列里还有数据,
那么堵塞等待一段时间( linger interval)。如果超时了,那么强制关闭连接。设置等于0
的值表示直接强制关闭连接。超时上限为65535。

10. SO_TIMEOUT

Set a timeout on blocking Socket operations:

ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();

The option must be set prior to entering a blocking
operation to take effect. If the timeout expires and the
operation would continue to block,
java.io.InterruptedIOException is raised. The Socket is
not closed in this case.

SO_TIMEOUT选项用于对read()操作设置timeout,单位为毫秒。当timeout发生时,会抛出
InterruptedIOException。设置不大于0的值会令read()操作永远堵塞。

11. SO_SNDBUF

Set a hint the size of the underlying buffers used by the
platform for outgoing network I/O. When used in set, this is a
suggestion to the kernel from the application about the size of
buffers to use for the data to be sent over the socket. When
used in get, this must return the size of the buffer actually
used by the platform when sending out data on this socket.

设置SO_SNDBUF表示向内核建议socket发送缓冲区的大小。获取SO_SNDBUF一定返回实际发送缓冲区
的大小。单位字节。

12. SO_RCVBUF

Set a hint the size of the underlying buffers used by the
platform for incoming network I/O. When used in set

kupbezrecepty.com

, this is a
suggestion to the kernel from the application about the size of
buffers to use for the data to be received over the
socket. When used in get, this must return the size of the
buffer actually used by the platform when receiving in data on
this socket.

设置SO_RCVBUF表示向内核建议socket接收缓冲区的大小。获取SO_RCVBUF一定返回实际接收缓冲区
的大小。单位字节。

13. SO_KEEPALIVE

When the keepalive option is set for a TCP socket and no data
has been exchanged across the socket in either direction for
2 hours (NOTE: the actual value is implementation dependent),
TCP automatically sends a keepalive probe to the peer. This probe is a
TCP segment to which the peer must respond.
One of three responses is expected:
1. The peer responds with the expected ACK. The application is not
notified (since everything is OK). TCP will send another probe
following another 2 hours of inactivity.
2. The peer responds with an RST, which tells the local TCP that
the peer host has crashed and rebooted. The socket is closed.
3. There is no response from the peer. The socket is closed.
The purpose of this option is to detect if the peer host crashes.

SO_KEEPALIVE启用时,当tcp连接中没有数据流动超过2小时时,系统主动发送一个keepalive探寻包(probe)给
对方,对方必须响应这个包。收到ack的时候表示连接正常。满足以下条件时视为连接关闭:

  1. 对方返回了RST
  2. 对方没有任何返回

14. SO_OOBINLINE

When the OOBINLINE option is set, any TCP urgent data received on
the socket will be received through the socket input stream.
When the option is disabled (which is the default) urgent data
is silently discarded.

该选项默认disable,当enable时,表示urgent data直接在接收方read()操作中返回(和普通数据混在一起),
否则接收方直接忽略该数据。