【Java 网络编程】客户端 Socket 配置 ( 超时时间 | 端口复用 | Nagle 算法 | 心跳包机制 | 连接关闭机制 | 缓冲区大小 | 性能权重设置 | 紧急数据设置 )



I 设置读取超时时间



1. 设置 Socket 超时时间 , 该超时时间没有实际的概念 , 用于设置与阻塞相关操作的超时时间 , TCP 连接中有两个需要阻塞的操作 :

  • ① 连接服务器操作 ;
  • ② 等待读取服务器发送给客户端的数据 ;

连接超时时间可以单独设置 , 这里设置的读取超时时间 ;

2. 单位 : 毫秒 ( ms ) ;

3. 设置一个非 0 的超时时间 , 当与 Socket 对象关联的 InputStream 输入流执行 read() 操作时 , 其阻塞时间为这个超时时间 , 如果超过了该时间还没有收到任何数据 , 就会抛出异常 ;

socket.setSoTimeout(3000);


II Socket 复用绑定端口设置



设置是否可以复用 Socket 绑定的地址和端口号 : setReuseAddress( true ) ;

socket.setReuseAddress(true);

Socket 连接在建立时 , 会使用之前绑定本地的 IP 地址和端口号 , 这个端口号在使用之后 , 2 分钟之内不允许再次使用 ; 进行了该设置之后 , 可以在连接关闭之后 , 马上使用该本地 IP 地址和端口号 ;



III 开启 Nagle 算法 ( 沾包 )



1. 前提 : TCP 发送数据后 , 接收方会反馈已经接受到的数据 ;

2. 示例 : 客户端如果向服务器端发送 1 字节数据 , 服务器端需要反馈 ACK 信息 , ACK 的命令其大小要比传输的数据还要大 , 其消耗要高于实际的数据传输消耗 ;

3. Nagle 算法引入 : 为了避免上述情况的消耗 , 便有了 Nagle 算法 ;

  • ① 服务器端处理 : 其原理是接收端接到数据后 , 如果数据很小 , 那就多接收几个数据 , 然后将反馈信息一起回送给发送端 ;
  • ② 客户端处理 : 对应的客户端处理便是一条数据发送之后 , 会等待服务器端反馈 , 然后这段时间内如果又有新的数据要发送 , 那么就会将这些数据缓存起来 , 等待前面的数据反馈信息回送之后 , 将发送端缓存的这些数据全部发送出去 ; 这样就出现了沾包的情况 ;

4. Nagle 算法好处 : Nagle 算法有效的减少了因发送少量数据 , 而产生大量的 ACK 回送包的数据量 ; 优化网络带宽 ;

在需要低延迟传输的情况下是需要关闭该算法的 , 该算法会导致数据沾包情况出现 ;

socket.setTcpNoDelay(true);


IV 心跳包机制



设置了 setKeepAlive(true) 之后的效果 : 如果 TCP 连接在 2 小时之内没有数据传输 , 客户端就会发送心跳包 , 服务器端会会送消息 , 如果客户端没有收到服务器端反馈信息 , 就认为该 TCP 连接已经断开 , 客户端会抛出异常信息 ;

//在长时间 ( 2 小时 ) 没有数据交互 , 是否需要发送心跳包确认连接
socket.setKeepAlive(true);


V 连接关闭处理



1. 连接关闭处理 : 对于连接关闭行为处理方式设置 , 调用 setSoLinger 函数设置 ;

2. 关闭情况说明 : 当 Socket 对象调用 close 方法关闭连接时 , 有可能缓冲区中还有数据没有发送完成 , 这个方法就是用于处理这部分缓冲区数据的 ;

3. setSoLinger 函数原型 :

    /**
     * Enable/disable {@link SocketOptions#SO_LINGER 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 1.1
     * @see #getSoLinger()
     */
    public void setSoLinger(boolean on, int linger) throws SocketException

4. setSoLinger 参数解析 :

  • ① boolean on : TCP 连接关闭处理功能是否打开 , 默认是关闭的 ( false ) ;
  • ② int linger : Socket 调用 close 方法后 , 需要阻塞等待缓冲区数据发送的时间 , 单位毫秒 ;

5. 默认状态 : 如果 boolean on 设置成false , 不处理连接的缓存数据 , 调用 close 会立刻关闭连接 , 系统底层会操作输出流发送剩余缓存数据 , 将缓冲区中的数据发送给连接对方 ; 如果设置 false 不会产生阻塞操作 ;

6. 开启连接关闭处理 : setSoLinger( true , 20 ) 情况 , 如果设置 boolean on 参数为 true , int linger 参数设置一个大于等于 0 的参数 , 那么在关闭的时候 , 阻塞 linger 毫秒 , 之后缓冲区如果还有数据 , 就会被丢弃 , 直接向连接对方发送结束命令 , 无需经过超时等待 ;

超时等待是数据达到对方并返回的最长等待时间 ( MSL ) ;

7. 开启连接关闭处理 ( 不阻塞 ) : setSoLinger( true , 0 ) 情况 , 如果设置成 0 , 那么其后果是不阻塞 , 也不让系统接管输出流 , 立刻丢弃缓冲区数据 , 向对方发送 RST 命令 ;



VI Socket 紧急数据内敛设置



//设置紧急数据是否内敛 , 默认情况时 false 关闭的 ; 
socket.setOOBInline(true);

1. 紧急数据 : 紧急数据是 Socket 对象通过调用 sendUrgentData 发送出去的数据 ; 该方法参数是一个 int 值 , 仅有最低的 8 位是有效的 ;

2. 紧急数据透明特性 : 紧急数据默认情况下与上层的数据是隔离的 , 如客户端给服务器端发送了一条紧急数据 , 服务器端照常接收处理普通数据 , 其不影响数据的接收与处理 , 也不知道客户端发送了紧急数据 ;

3. 接收紧急数据 : 如果服务器端想要接收客户端发送的紧急数据 , 那么需要在获取 Socket 输入流之前设置 socket.setOOBInline(true) , 才能在接收数据时 , 读取到紧急数据 ;

4. 设置紧急数据 : setOOBInline 方法设置紧急数据是否内敛 , 默认情况时 false 关闭的 ;

5. 适用场景 : 使用紧急数据当做心跳包 ;

不建议设置紧急数据内敛 , 可能会影响实际数据的正确性 ;



VII Socket 设置缓冲区大小



1. 缓冲区大小设置包括两个缓冲区设置 :

  • ① 发送缓冲区设置 :
socket.setSendBufferSize(64 * 1024 * 1024);
  • ② 接收缓冲区设置 ;
socket.setReceiveBufferSize(64 * 1024 * 1024);

2. 缓冲区作用 : 缓冲区大小默认 32 KB , 缓冲区大小不是要等到有 32 KB 数据才进行发送和接收 , 而是如果发送和接收的数据大于 32 KB , 如 33 KB , 就会将数据拆分成两包 , 32 KB 和 1KB , 然后进行发送和接收操作 ;

注意设置一定要在连接之前设置 , 连接后设置时无效的 ;



VIII Socket 连接性能参数设置



1. 调用 Socket 对象的 setPerformancePreferences 方法 , 设置连接的性能参数 ; 连接有以下三个性能参数 :

  • ① 连接时间 ;
  • ② 往返延迟 ;
  • ③ 带宽 ;

2. 设置的是权重不是具体性能参数 : 设置的值不是具体的参数 , 而是连接的性能权重 , 对哪个性能要求比较高 ;

3. 连接时间 : 如果该 Socket 的连接很频繁 , 连接后传一个数据 , 马上断开 , 这时候比较看重连接时间性能 , 此时可以将第一个参数设置成 10 , 后两个参数设置成 1 , 表示注重连接时间性能 ;

//设置 连接时间 性能参数较重要
socket.setPerformancePreferences(10, 1, 1);

4. 往返延迟 : 如果开发的是网游服务器 , 此时对延迟很看重 , 这时候可以将第二个参数设置成比较高的权重 ;

//设置 往返延迟 性能参数较重要
socket.setPerformancePreferences(1, 10, 1);

5. 带宽 : 如果开发的是音视频服务器 , 注重带宽性能 , 此时需要将第三个参数设置成较高的权重 ;

//设置 带宽 性能参数较重要
socket.setPerformancePreferences(1, 10, 1);

6. 上面的延迟和带宽的性能是互斥的 , 延迟低 , 就意味着很小的包就要发送一次 , 其带宽就低了 , 延迟高了 , 每次积累很多数据才发送 , 其带宽就相应的提高了 ;

7. 函数原型 :

    /**
     * Sets performance preferences for this socket.
     *
     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
     * may offer alternative protocols which have different performance
     * characteristics than TCP/IP.  This method allows the application to
     * express its own preferences as to how these tradeoffs should be made
     * when the implementation chooses from the available protocols.
     *
     * <p> Performance preferences are described by three integers
     * whose values indicate the relative importance of short connection time,
     * low latency, and high bandwidth.  The absolute values of the integers
     * are irrelevant; in order to choose a protocol the values are simply
     * compared, with larger values indicating stronger preferences. Negative
     * values represent a lower priority than positive values. If the
     * application prefers short connection time over both low latency and high
     * bandwidth, for example, then it could invoke this method with the values
     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
     * latency, and low latency above short connection time, then it could
     * invoke this method with the values {@code (0, 1, 2)}.
     *
     * <p> Invoking this method after this socket has been connected
     * will have no effect.
     *
     * @param  connectionTime
     *         An {@code int} expressing the relative importance of a short
     *         connection time
     *
     * @param  latency
     *         An {@code int} expressing the relative importance of low
     *         latency
     *
     * @param  bandwidth
     *         An {@code int} expressing the relative importance of high
     *         bandwidth
     *
     * @since 1.5
     */
    public void setPerformancePreferences(int connectionTime,
                                          int latency,
                                          int bandwidth)
发布了252 篇原创文章 · 获赞 1013 · 访问量 168万+

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/100528521