影响Socket数据接收发送的选项设置

为了叙述比较方便,我们先从JavaSocket模型说起
JavaSocket模型
        javaSocket模型如下图所示:

   Java Socket运行在JVM或者底层OS提供的native socket之上,所有对Java Socket的操作都反映到native socket。所以从Socket发展渊源看,影响Socket性能的选项也必然是native socke暴露给Javat的一些设置。
Socket Options
这些选项主要影响native socket如何发送和接收数据,从而影响Socket的性能。这些选项以及支持的JDK版本入下表所示:
#
选项
Java版本
Default
说明
1
TCP_NODELAY
1.1+
false
设置是否尽快发送packer,而不管其大小
2
SO_TIMEOUT
1.1+
0
数据读取超时,0表示永不超时
3
SO_LINGER
1.1+
false
设置socket关闭后,没有发送的数据包逗留时间
4
SO_RCVBUF
1.2+
 
接收Buffer
5
SO_SNDBUF
1.2+
 
发送Buffer
6
SO_KEEPALIVE
1.3+
false
连接存活探测
7
OOBINLINE
1.4+
false
紧急数据处理设置
8
SO_REUSEADDR
1.4+
false
地址重用设置
1)TCP_NODELAY
因为有Buffer的使用,TCP协议一般情况(Nagle算法) ,小数据包都是和其他大数据包一块打包发送,然后后续发送数据包之前需要收到已发送包的确认,否则一直等待。因为数据包的捆绑传输,远程不能及时确认发送的数据包,如果应用大部分传输小数据包的话,会明显感觉信息处理速度会降下来。最明显受此影响的是游戏应用,因为鼠标的移动传输都是小数据包。在这样的环境,setTcpNoDelay(true)可以禁用Buffer,让数据尽快发出去。
2)SO_TIMEOUT
一般情况下,当从socket读取数据时,read方法会阻塞必要长时间获取足够(而不是必须一定指定长度)的数据,或者永远block下去。通过设置SO_TIMEOUT,可以控制最长Block多长时间,在时间超市后,将抛出InterruptedIOException 。
3)SO_LINGER
SO_LIGER选项处理在socket关闭后还没有发出去的数据如何处理。缺省条件下,在socket close方法立即返回后,系统仍将继续发送未发送出去的数据。如果逗留(linger)时间设置为0,那么没有发送的包将被丢弃;如果设置一个时间值t秒,close方法会block等待数据传输和响应接收,当时间结束之后,socket关闭,没有发送出去的数据包和响应将丢弃不予处理。逗留时间不能设置为负数,否则将抛出IllegalArgumentException,但是getSoLinger可以返回-1,表示此选项还没有启用。逗留时间最大允许设置65535秒(超过18小时,对于一般的应用已足够了)。总体上说,平台的默认值非常恰当,我们不需要特别设置。
4)SO_RCVBUF
大部分TCP协议栈使用Buffer提高网络性能。大容量Buffer倾向于提高高带宽的网络性能,而低速网络使用小容量Buffer更合适。一般说来,传输连续大块数据的协议,如FTP、HTTP,使用大容量Buffer更合适,而小数据量、非连续数据包,如Telnet和很多关注交互性的服务协议建议采用小容量Buffer。这里的内容也上面提到的TCP_NODELAY发生了呼应。具体设置对象合适,没有定论,只能按照上面提到的准则进行微调,另外需要注意setReceiveBufferSize只是给底层实现提了一个建议值,底层可以忽略,所以为了验证设置是否成功,需要set之后get确认一下。
5)SO_SNDBUF

设置发送Bufffer,对socket传输数据影响和SO_RCVBUF类似

6)SO_KEEPALIVE
如果SO_KEEPALIVE设置为true,socket会间歇(这个间歇时间一般是2小时)地在空闲连接上发送一个包给服务器,以确认服务器没有crash。如果请求没有被响应,客户端继续尝试,直到在12分内没收到响应,客户端断开socket。如果没有设置或者设置为false,那么不活动的客户端将可能永远也感知不到服务段已经crash。如果客户端是活跃的,那么这个值没有设置的必要。如果想把默认值从2小时给成其他时间,需要修改操作系统内核参数(Linux)。探测时间间隔设置合适可以作为应用心态使用,但不能完全替代,因为应用心跳需要判断一些业务状态,而不仅仅是链路断开与否。另外,还需要注意keepalive时间值修改是全局有效的,不仅仅客户端自己,所有平台上的Socket应用都会收到影响。
在Linux上设置位置在

/proc/sys/net/ipv4/tcp_keepalive_time        每次确认包发送的间隔时间 
/proc/sys/net/ipv4/tcp_keepalive_intvl        每次确认最多重发次数 
/proc/sys/net/ipv4/tcp_keepalive_probes    重试间隔

7)OOBINLINE
紧急数据被立即发送,接收端收到通知后也先于其他数据处理。在发送紧急数据时,如果必要(?)任何当前Buffer内的数据都会被先flush。接收端如何处理这个数据存在一些模糊。有的平台和API把它和平常数据分开处理,然后大多数解决方案是把它放到普通数据队列,让应用自己去从队列中获取处理。
缺省条件下,java倾向于忽略。如果想伴随平常数据接收,需要setOOBInline(true),这样任何紧急数据达到使,将像普通数据一样被放置到inputstream。Java不区分是否紧急数据,仅是高知底层实现。
8)SO_REUSEADDR
当socket被关闭时,它不会立即释放本地地址,因为此时非常有可能网络连接还在打开状态,而是等上那么一小会,确保收下仍在网络中传输的数据包。而底层系统对数据包不做任何处理,仅仅保证没有其他socket邦定到这个地址,以免发生数据错乱。
如果服务端口是个随机的端口,这不是一个问题,然而对于像23这样著名端口,因为他阻止了其他socket使用这个端口。(有什么问题吗?)如果设置开启这个选项,在数据对于前面socket已经无效的条件下重用端口。
需要注意此选项必须在邦定具体端口端口之前设置,否则无效。

服务设置

针对一些不同的Internet服务设置不同的服务级别是一种有效的Internet资源利用和服务体现。例如视频/音频服务需要高带宽、低延时,但允许少量丢包,而email等对贷款和延时不太关注,主要在合理的时间传输到就无伤大雅。这和分布式CAP理论一样,满足所有美好特性的服务很难达成,一是资源部允许,而是没有必要。

TCP定义了四种服务类型,但这些不一定在所有路由器等网络设备和本地TCP栈支持,这些设置仅是给底层实现一个提示

1)低成本,0x02

2)高可靠性,0x04

3)最大吞吐量,0x08

4)最小延时,0x10

这四种服务可以组合设置,通过位或运算设置:

public void setTrafficClass(int trafficClass) throws SocketException

比如我们设置视频服务的设置s.setTrafficClass(0x08 | 0x10);

在Java5之后增加了一个不同方法设置这些服务偏好:

public void setPerformancePreferences(int connectionTime, int latency, int bandwidth)

这个方法用数值表达在连接时间、延时、贷款一个偏好。如setPerformancePreferences(1,101,2),表示最看重latency,其次bandwidth,最不关注的是connectionTime。

猜你喜欢

转载自xiaonanforever.iteye.com/blog/2000466