Socket(三)

1. 设置Socket选项

Socket选项指定了Java Socket类所依赖的原生socket如何发送和接受数据,对于客户端,java有9种选项

  • TCP_NODELAY
  • SO_BINDADDR
  • SO_TINEOUT
  • SO_LINGER
  • SO_SNDBUF
  • SO_RCVBUF
  • SO_KEEPALIVE
  • OOBINLINE
  • IN_TOS

2. TCP_NODELAY

public void setTcpNoDelay(boolean on)throws SocketException
public boolean getTcpNoDelay() throws SocketException

设置该选项可一确保包会尽可能地发送,无论包的大小。正常情况下,小数据包(一字节)在发送前会组合成更大的包。在发送另一个包之前,本地主机要等待远程系统对前一个包的确认。这称为Nagle算法。该算法的问题是,如果远程系统没有足够快的确认发送回本地系统,那么依赖于小数据量信息稳定传输的应用程序会变得很慢。设置TCP_NODELAY为true可以打破这种缓冲模式,这样所有的包一旦就绪就会全部发送。setTcpNoDelay(true)关闭了Socket的缓冲,这两个方法都声明为抛出一个SocketException异常。如果底层Socket实现不支持TCP_NODELAY选项,就会抛出这个异常。

3. SO_LINGER

public void setSoLinger(boolean on ,int seconds)throws SocKetException
public int getSoLinger()throws SocketException

该选项指定了Socket关闭时如何处理未发送的数据报。默认情况下,close()方法将立即返回,但系统仍然会继续尝试发送剩下未有发送的数据。如果seconds(延迟时间)设置为0,那么当socket关闭时,所有没有发送的数据都将被丢弃。如果设置为任意数,close()方法会被阻塞(阻塞时间为指定的延迟时间),等待发送数据和确认。如果底层Socket不支持该选项,会抛吹SocKetException。如果getSoLinger返回-1说明该选项被关闭了,会使用系统的默认选项。

4. SO_TIMEOUT

public void setSoTimeout(int milliseconds)throws SocketException
public void getSoTimeout() throws SocketException

正常情况下,尝试从Socket读取数据时,read()调用会阻塞尽可能长的时间来得到足够的字节,设置这个选项可以确保这次调用阻塞时间不会超过我们设置的时间,如果超过了会抛出InterruptedException异常,不过Socket并不会断开,下次还是可以调用read再次读取。超时时间单位为毫秒,0被解释为无限超时(这也是默认值)。当底层Socket不支持该选项时,同样会抛出SocketException异常

5. SO_RCVBUF和SO_SNDBUF

TCP使用缓冲区提升网络性能,较大的缓冲区会提升快速连接的性能,而较慢的拨号连接利用较小的缓冲区会有更好的表现。一般来说传输连续的大数据块时,可以从缓冲区受益;而对于交互式会话的小数据量传输,大缓冲区则会受益很小。最大带宽可以由缓冲区大小/延迟来得到,延迟是与网络硬件相关的,所以我们只能从缓存区的角度去提升网络带宽。SO_RCVBUF选项控制用于网络输入的建议的接受缓冲区大小。SO_SNDBUF选项则控制用于网络输出的建议大小。(建议大小,说明底层实现可以忽略该建议)

public void setReceiveBufferSize(int size) throws SocketException, IllegalArgumentException
public int getReceiveBufferSize()throws SocketException
public void setSendBufferSize()throws SocketException, IllegalArgumentException
public int getSendBufferSize()throws SocketException

看起来可以使用上面的方法独立的设置输入缓存区和输出缓冲区,但实际上缓存区会设置为输入和输出缓冲区中间较小的那一个。 一般来说,如果你发现你的应用不能充分利用可用带宽(例如,你有一个25Mb/s的Internet连接,但是数据传输速率仅为1.5Mb/s),那么可以试着增加缓冲区的大小。相反地,如果存在丢包现象和拥塞现象,则要减少缓冲区大小。

6. SO_KEEPALIVE

如果打开了该选项,客户端会偶尔通过一个空闲连接发送一个数据包,以确保服务器未崩溃(类似于服务器集群中的心跳机制)。如果服务器没有响应这个包,客户端会持续尝试11分钟多的时间,直到接受到响应为止。如果还没有接受到响应,客户端就会主动关闭Socket。如果没有设置该选项,不活动的客户端会永远存活下去,而不会注意到服务器已经奔溃。该选项的默认值为false

public void setKeepAlive(boolean on) throws SocketException
public boolean getKeepAlive()throws SocketException

7. OOBINLINE

TCP包括一个可以发送单字节带外(Out of Band,OOB)“紧急”数据的特性。这个数据会立即发送,此外当紧急方收到紧急数据时会得到通知,在其他已收到的数据之前处理这个数据。发送方法的名为sendUrgentData()

public void sendUrgentData(int data)throws IOException

这个方法几乎会立即发送参数中最低字节位。如果必要,当前缓存的所有数据将首先刷新输出,接受端会将紧急数据以适当的顺序放在正常接收的数据队列中,告诉应用程序紧急数据已经可用,让应用程序在队列中查找紧急数据。默认情况下,java会忽略从Socket接受的紧急数据,如果要接受的话,可以使用下面的方法:

public void setOOBInline(boolean on) throws SocketException
public boolean getOOBInline()throws SocketException

一旦打开OOBInline,到达的任何仅仅数据会以正常的方法放入Socket的输入流中等待读取,Java不区分紧急数据和非紧急数据,这使得它不能理想的发挥作用。

8. SO_REUSEADDR

一个Socket关闭时,可能不会立即释放本地端口,尤其是当Socket关闭时若仍有一个打开的连接,就不会释放本地端口。有时可能需要等一段时间,确保接收所有要发送到这个端口的延迟数据包,Socket关闭时这些数据包仍然可能在网上传播。心痛过不会对接收到的延迟包作任何处理,只是希望这些数据不会意外掉落到绑定到统一端口的新进程。如果使用随机端口,这不是大问题,但是Socket绑定到一个已知端口,会阻止其他Socket使用这个端口。如果开启该选项(默认为关闭),就允许另一个Socket绑定到这个端口,即使此时仍有可能存在前一个Socket接收到的数据。由下面两个方法确定:

public void setReuseAddress(boolean on)throws SocketException
public boolean getReuserAddress()throws SocketException

要正常使用上面方法,setReuseAddress()必须在为这个端口绑定新Socket之前调用。这意味着Socket必须使用无参数构造函数以非连接状态创建,然后调用setReuseAddress(true),再使用connect()方法连接Socket。之前连接的Socket和重用老地址的新Socket都必须设置SO_REUSEADDR为true,这样才会生效。

9. IP_TOS服务类型

不同类型的Internet服务有不同的性能需求。例如,为了得到较好的性能,视频需要相对较高的带宽和较短的延迟,而电子邮件可以通过低带宽的连接传递,甚至延迟几个小时都不会造成很大的伤害。服务类型存储在IP首部中一个名为IP_TOS的8位字段中。Java运行你使用 下面两个方法检查和设置Socket放在这个字段中的值:

public int getTrafficClass()throws SocketException
public void setTrafficClass() throws SocketException

业务类型流以0-255之间给出。由于这个值要复制到TCP首部中的一个8位字段,所以只使用这个int的低字节,超出个范围的值会导致IllegalArgumentException异常。在21世纪的TCP栈中,这个字节的高6位包含一个差分服务代码点(DSCP)值,低两位包含一个显示拥塞通知(ECN),因此DSCP允许有64种不同的业务流。不过要由各个网络和路由器指定这64个不同的DSCP值分别代表什么含义。

PHB(逐跳行为)二进制值用途
默认00000Best-effort(尽力)业务流
加速转发101110低损耗、低延迟、低抖动业务流。通常仅限于网络容量的30%或更低
保证转发多个保证最多以一个指定速率传送
类选择器xxx000与IPv4 TOS首部向后兼容(存储在前3位中)
Socket s=new Socket("www.baidu.com",80);
s.setTrafficClass(0xB8);

DSCP值并不是服务的严格保证。实际上,尽管一些网络会在内部参考DSCP值,但包越过ISP时,这个信息几乎会被忽略。

10. Socket异常

Socket类大大多数方法都声明抛出IOException或其子类java.net.SocketException:

public class SocketException extends IOException

不过仅仅知道发生了问题,者对于处理问题往往是不够的。是不是因为远程主机忙而拒绝连接?还是因为没有服务在这个端口上监听而导致远程主机拒绝连接?或者是否因为网络拥塞或主机崩溃导致连接超时?SocketException有几个子类,可以对出现什么问题以及为什么会出问题提供有关的更多信息。

public class BindException extends SocketException
public class ConnectException extends SocketException
public class NoRouteToHostException extends SocketException

如果试图在一个正在使用的端口上构造Socket或ServerSocket对象,或者你没有足够的权限使用这个端口,就会抛出BindException异常。当连接被远程主机拒绝时,而拒绝的原因是由于主机忙或没有进程在监听该端口,此时就会抛出ConnectException异常。最后一点,NoRouteToHostException异常表示连接已经超时。java.net包还包括了ProtocolException异常,它是IOException的直接子类:

public class ProtocolException extends IOException

当从网络接收的数据违反TCP/IP规范时,会抛出这个异常。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值