NIO与Socket笔记 :实现Socket 通信[ 三 ]

Socket 类的使用

ServerSocket类作用是搭建 Socket的服务端环境, 而 Socket类的主要作用是使 Server 与 Client进行通信。

绑定 bind 与 connect 以及端口生成的时机

public void bind (SocketAddress bindpoint) 方法 的作用是将套接字绑定 到本地地址 。 如 果地址为 null,则系统将随机挑选一个空闲的端 口和一个有效的本地地址来绑定套接字 。

在 Socket通信的过程中,服务端和客户端都需要端口来进行通信。

bind()方法就是将客户端绑定到指定的端口上,该方法要优先于 connect()方法执行,也就是先绑定本地端口再执行连接方法 。

连接与超时

public void connect (SocketAddress endpoint, int timeout)方法的作用是将此套接宇连接 到服务端,并指定一个超时值。 超时值是 0意味着无限超时。 在 Windows操作系统中,默 认的超时时间为 20s。

获得远程端口与本地端口

public int getPort()方法的作用是返回此套接宇连接到的远程端口 。

public int getLocalPort()方法的作用是返回此套接字绑定到的本地端口 。

获得本地 lnetAddress 地址与本地 SocketAddress 地址

public InetA ddress getLocalAddress()方法的 作用是 获取套接字绑定的本 地 InetAddress 地址 信息。

public SocketAddress getLocalSocketAddress() 方法的作用是返回此套接字绑定的端点的 Socket-Address地址信息。

获得远程 lnetAddress 与远程 SocketAddress()地址

public InetA ddress getlnetAddress(): 返回此套接字连接到的远 程 的 InetAddress地址。 如果套接字是未连接的,则返回 null。

public SocketAddress getRemoteSocketAddress(): 返回此套接字远程端点的 SocketAddress 地址,如果未连接 , 则返回 null。

套接字状态的判断

public boolean isBound()方法的作用是返回套接字的绑定状态。 如果将套接字成功地绑 定到一个地址,则返回 true。

public boolean isConnected()方法的作用是返回套接字的连接状态。 如果将套接字成功 地连接到服务端,则为 true。

public boolean isClosed()方法的作用是 返回 套接字 的关闭状态 。 如果已经关闭了套接 字, 则返回 trueo

开启半读与半写状态、

public void shutdownlnput()方法的作用是将套接字的输入流置于“流的末尾 EOF”,也 就是在套接字上调用 shutdownlnput()方法后从套接字输入流读取内容,流将返回 EOF (文 件结束符) 。 发送到套接字的输入流端的任何数据都将在确认后被静默丢弃 。 调用此方法的 一端进入半读状态( read-half),也就是此端不能获得输入流,但对端却能获得输入流 。一端 能读,另 一端不 能读,称为半读。

public void shutdownOutput()方法的作用是禁用此套接字的输出流。 对于 TCP套接字, 任何以前写人的数据都将被发送,并且后跟 TCP 的正常连接终止序列 。 如果在套接字上调 用 shutdownOutput()方法后写入套接字输出流,则该流将抛出 IOException。 调用此方法的 一端进入半写状态( write-half)也就是此端不能获得输出流。 但对端却能获得输出流。 一 端能写,另一端不能写,称为半写 。

输出流被屏蔽后不能再使用输出流写出数据 。

判断半读半写状态

public boolean islnputShutdown():返回 是否关 闭 套接字 连接的半 读状态 (read-half)。 如果己关闭套接字的输入, 则返回 true。

public boolean isOutputShutdown():返回是否关闭套接字连接的半写状态 (write-half)。 如果已关闭套接字的输出,则返回 true。

Socket 选项 TcpNoDelay

public void setTcpNoDelay(boolean on)方法的作用是启用/禁用 TCP NODELAY (启用/ 禁用 Nagle 算法) 。 参数为 true,表示启用 TCP_NODELAY ;参数为 false,表示禁用 。

public boolean getTcpNoDelay()方法的作用是测试是否启用 TCP_NODELAY。 返回值 为是否启用 TCP_NODELAY 的 boolean值。

Nagle算法简介

Nagle算法是以它的 发明人 JohnNagle 的名字命名的,该算法可以将许多要发送的数据进行本地缓存(这一过程称为 nagling),以减少发送数据包的个数来提高网络软件运行的效率,这就是 Nagle算法被发明的初衷。

Nagle算法最早出现在 1984年的福特航空和通信公司,是解决 TCP/IP拥塞控制的方 法。 这个算法在当时将福特航空和通信公司的网络拥塞得到了控制,从那以后这一算法得到 了广泛应用 。

使用 Nagle算法的数据传输过程是在第一个 ACK确认之前,将要发送的数据放人缓存 中,接收到 ACK 之后再发送一个大的数据包,以提升网络传输利用率。

举个例子,客户端 调用 Socket 的写操作将一个 int型数据 123456789 (称为 A 块)写人到网络中,由于此时连 接是空闲的(也就是说,还没有未被确认的小段),因此这个 int类型的数据就会被马上发 送到服务端 。 接着,客户端又调用写操作写入“ \r\n”(简称 B 块),这个时候,因为 A 块的 ACK 没有返回,所以可以认为 A 块是一个未被确认的小段,这时 B 块在没有收到 ACK 之 前是不会立即被发送到服务端的,一直等到A块的ACK收到(大概40ms之后), B块才被发送 。

A 块数据的 ACK 为什么 40ms 之后才收到 ? 这是因为 TCP/IP 中不仅仅有 Nagle算法,还有一个 TCP “确认延迟( Delay) ACK”机制,也就是当 服务端收到数据之后,它并不会马上向客户端发送 ACK,而是会将 ACK 的发送延迟一段时 间(假设为 t),它希望在 t时间内服务端会向客户端发送应答数据,这样 ACK 就能够和应 答数据一起发送,使应答数据和 ACK 一 同发送到对方,节省网络通信的开销 。

Nagle 算 法是把 要 发送的数据放在 本 地缓存中,这就造 成客户端与服务端之间交互并不是高互动的,是有 一 定延迟的,因此,可以使用 TCP NODELAY 选项在套接字中开启或关闭这个算法 。

如果采用 Nagle算法,那么一个数据包要“攒到”多大才将数据进行发送呢?

要“攒 到” MSS 大小才发送!什么是 MSS 呢?

MSS (Maximum Segment Size)即最大报文段长 度。 在TCP/IP中,无论发送多少数据,总是要在数据前面加上协议头, 同时,对方接收到 数据,也需要发送回 ACK 以表示确认 。 为了尽可能地利用网 络带 宽, TCP 总是希望尽可能 一 次发送足够大的数据,此时就可以使用 MSS 来进行设 置 。 MSS 选项 是 TCP/IP 定 义的 一 个选项, 该选项用于在TCP/IP连接建立时, 收发双方协商通信时每一个报文段所能承载的 最大数据长度,它的计算方式如下 :

MSS = MTU - 20 字 节的 TCP 报头 - 20 字节的 IP 报头

在以太网环境下, MSS值一般就是 1500-20-20= 1460字节。

TCP/IP希望每次都能够以 MSS (最大尺寸)的数据块来发送数据,以增加每次网络传输的数据量。

Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Nagle算 法的基本含义是在任意的时刻,最多只能有一个未被确认的小段 。

所谓“小段”指的 是小 于 MSS 的数据块;所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK 确认该数据已收到 。

TCP_NODELAY 选项可以控制是否采用 Nagle算法 。 在默认情况下,发送数据采用的 是 Nagle算法,这样虽然提高了网络吞吐量 ,但是实时性却降低了,在一些交互性很强的应 用程序中是不允许的。 使用TCP_NODELAY选项可以禁止Nagle算法。

通过前面的一些知识点的介绍,可以分析出以下两点 。
1 )如果要求高实时性,那么有数据发送时就要马上发送,此时可以将 TCP NODELA Y

选项设置为 true,也就是屏蔽了 Nagle算法。 典型的应用场景就是开发一个网络格斗游戏, 程序设计者希望玩家 A 每点击一次按键都会立 即在玩家 B 的计算机中得以体现,而不是 等 到数据包达到最大时才通过网络一次性地发送全部数据,这时就可以屏蔽 Nagle算法 ,传人 参数 true就达到实时效果了。

2) 如果不要求高实时性, 要减少发送次数达到减少网络交互,就将 TCP NODELAY 设置为 false,等数据包累积一定大小后再发送。

Nagle 算 法适用于大包 、 高延迟的场合,而对于要求交互速度的 B/S 或 C/S 就不合适 了。 在 Socket创建的时候 ,默认都是使用 Nagle算法的,这会导致交互速度严重下降,因 此,需要屏蔽Nagle算法。 不过,如果取消了Nagle算法,就会导致TCP碎片增多,效率 可能会降低,因此,要根据实际的运行场景进行有效的取舍。

Socket 选项 SendBufferSize

Socket中的 SO_RCVB旧选项是设置接收缓冲区的大小的,SO_SNDBUF选项是设置发送缓 冲区的大小的 。

public synchronized void setSendBufferSize(int size)方法的作用是将此 Socket 的 SO_SND­B旧选项设置为指定的值。

平台的网络连接代码将 SO SNDB四选项用作设置底层网络 νo 缓存的大小的提示。由于 SO SNDB旧 是一种提示,因此想要验证缓冲区设置大小的应用程 序应该调用 getSendBufferSize()方法。参数 size用来设置发送缓冲区的大小, 此值必须大于 0。

public int getSendBufferSizeO方法的作用是获取此 Socket的 SO_SNDBUF选项的值,该值 是平台在 Socket上输出时使用的缓冲区大小。 返回值是此 Socket的 SO_SNDB旧选项的值。

设置合适的发送缓冲区大小能 提高程序运行的效率 。

Socket 选项 Linger

Socket 中的 SO_LINGER 选项用来控制 Socket关闭 close()方法时的行为 。

在默认情况 下,执行 Socket 的 close()方法后,该方法会立即返回,但底层的 Socket 实际上并不会立即 关闭,它会延迟一段时间 。

在延迟的时间里做什么呢?

是将“发送缓冲区”中的剩余数据在 延迟的时间内继续发送给对方,然后才会真正地关闭 Socket连接。

public void setSoLinger(boolean on, int linger)方法的作用是启用/禁用具有指定逗留时 间(以秒为单位)的 SO LINGER。

最大超时值是特定于平台的。 该设置仅影响套接字关闭。 参数 on 的含义 为是否逗留,参数 linger 的含义为逗留时间,单位为秒 。

public int getSoLinger()方法的作用是返回 SO_LINGER 的设置。 返回-1 意味着禁用该 选项 。

该设置仅影 响套接字关闭 。 返回值代表 SO_LINGER 的设置 。

从 public void setSoLinger(boolean on, int linger)方法的源代码中可以发现以下几点内容。

1) on传入 false, SO_LINGER功能被屏蔽,因为对代码语句中的 new Boolean()传入了 false值。对参数 on传入 false值是 close()方法的默认行为, 也 就是 close()方法立即返回,但底层 Socket并不关闭,直到发送完缓冲区中的剩余数据,才 会真正地关闭 Socket的连接_

2) on传人 true, linger等于 0,当调用 Socket 的 close()方法时,将立即中断连接,也 就是彻底丢弃在缓冲区中未发送完的数据,并且发送一个 RST 标记给对方 。 此知识点是根 据 TCP 中的 SO_LINGER 特性总结而来的 。

3) on传人 true, linger大于 65535 时, linger值就被赋值为 65535。
4) on传入 true, linger不大于 65535 时, linger值就是传人的值。

5 )如果执行代码“ socket.setSoLinger(true,5)”,那么执行 Socket 的 close()方法时的行为随着数据量的多少而不同 , 总结如下。

口数据量小:如果将“发送缓冲区”中的数据发送到对方的时间需要耗时 3s,则close()方法阻塞 3s,数据会被完整发送, 3s 后 close()方法立即返回,因为 3<5。

口数据量大:如果将“发送缓冲区”中的数据发送到对方的时间需要耗时缸,则close()方法阻塞缸, 5s之后发送 RST标记给对方,连接断开,因为 8>5。

1. 在 on=true、 linger=0 时, close()万法立即返回且丢弃数据,并且发送 RST 标记

2. 验证:在 on=false 时, close()万法立即返回并且数据不丢失,正常进行 4 次“挥手”

3. 验证:如果只是调用 close()方法,则立即返回并且数据不丢失,正常进行 4 次“挥手”

4. 测试:在 on=true、 linger=10 时,发送数据耗时小于 10s 的情况

如果将“发送缓 冲区”中的数据发送给对方需要耗时 3s,则 close()方法阻塞 3s,数据 被完整发送,不会丢失 。

5. 测试:在 on=true、 linger=1 时,发送数据耗时大于 1s 的情况

如果将“发送缓冲区”中的数据发送给对方需要耗时 8s,则 close()方法阻塞 ls后连接 立即关闭,并发送 RST 标记给对方 。

Socket 选项 Timeout

setSoTimeout(int timeout)方法的作用是启用 /禁用带有指定超时值的 SO_TIMEOUT,以 毫秒为单位。

启用 timeOut特性必须在进入阻塞操作前被启用才能生效。 超时-值 必须是大于 0 的数 。 超时值为 0 被解 释为无穷大超时值 。

Socket 选项 OOBlnline

Socket 的选项 SO OOBINLINE 的作用是在 套接字上接收的所有 TCP 紧 急数据都将通 过套接字输入流接收。禁用该选项时(默认),将悄悄丢弃紧急数据。 OOB ( Out Of Bound, 带外数据)可以理解成是需要紧急发送的数据 。

setOOBinlin咖 e)方法的作用是启用 /禁用 OOBINLINE选项( TCP紧急数据的接收者),默 认情况下,此选项是禁用的 ,

即在套接字上接收的 TCP 紧急数据’被静默丢弃。

setOOBinlin咖 e)方法的作用是启用 /禁用 OOBINLINE选项( TCP紧急数据的接收者),默 认情况下,此选项是禁用的 , 即在套接字上接收的 Tσ 紧急数据’被静默丢弃。 如果用户希望接 收到紧急数据,则必须启用此选项。 启用时,可以将紧急数据内嵌在普通数据中接收。 注意,仅 为处理传人紧急数据提供有限支持。 特别要指出的是,不提供传人紧急数据的任何通知并且不存在区分普通数据和紧急数据的功能(除非更高级别的协议提供)。 参数on传人true表示启用 。OBINL时E,传入 他e表示禁用。 publicvoid setOOBinline(boolean o吟方法在接收端进行设置来决 定是否接收与忽略紧急数据。 在发送端,使用publicvoidsendUrgentData(intdata)方法发送紧急数据。

Socket类的publicvoid sendUrgentData (int data)方法向对方发送 1个单字节的数据, 但是这个单字节的数据并不存储在输出缓冲区中, 而是立即将数据发送出去, 而在对方程序 中并不知道发送过来的数据是由 OutputStream还是由 sendUrgentData(intdata)发送过来的。

Socket 选项 KeepAlive

Socket选项 so 阻 EPALIVE 的作用是在创建了服务端与客户端时,使客户端连接上服务 端.

当设置 so 阻EPALIVE为阳e时,若对方在某个时间(时间取决于操作系统内核的设置)内没有发送任何数据过来 那么端点都会发送一个 ACK 探测包到对方,探测双方的 TCP/IP 连 接是否有效(对方可能断电,断网) 。

如果不设置此选项,那么 当客户端着机时,服务端永远 也不知道客户端岩机了,仍然保存这个失效的连接。如果设置了 比选项,就会将此连接关闭 。

Socket 选项 TrafficClass

IP规定了以下 4种服务类型,用来定性地描述服务的质量。
1 ) IPTOS_LOWCOST ( Ox02 ): 发送成本低。
2 ) IPTOS_RELIABILITY ( Ox04): 高可靠性,保证把数据可靠地送到目的地。
3 ) IPTOS_THROUGHPUT ( Ox08 ): 最高吞吐量, 一次可以接收或者发送大批量的数据。

4) IPTOS_LOWDELAY ( OxlO): 最小延迟,传输数据的速度快,把数据快速送达目的地。

public void setTrafficClass(int tc)方法的作用是为从此 Socket上发送的包在 IP头中设置流量类别 (trafficclass)。
public int getTrafficClass()方法的作用是为从此 Socket上发送的包获取 IP头中的流量类别或服务类型 。
当向 IP头中设置了流量类型后, 路由器或交换机就会根据这个流量类型来进行不同的处理, 同时必须要硬件设备进行参与处理 。

猜你喜欢

转载自blog.csdn.net/zhanglong_4444/article/details/89002242