java socket 的参数选项解读

java socket中有很多参数可以选择,这篇博客的目的是沉淀出这些参数的语义和用法,供自己以后查阅。

1、java socket参数选项总览

在JDK1.6中有如下参数选项:

 1 public final static int TCP_NODELAY = 0x0001;
 2
 3 public final static int SO_BINDADDR = 0x000F;
 4
 5 public final static int SO_REUSEADDR = 0x04;
 6
 7 public final static int SO_BROADCAST = 0x0020;
 8
 9 public final static int IP_MULTICAST_IF = 0x10;
10
11 public final static int IP_MULTICAST_IF2 = 0x1f;
12
13 public final static int IP_MULTICAST_LOOP = 0x12;
14
15 public final static int IP_TOS = 0x3;
16
17 public final static int SO_LINGER = 0x0080;
18
19 public final static int SO_TIMEOUT = 0x1006;
20
21 public final static int SO_SNDBUF = 0x1001;
22
23 public final static int SO_RCVBUF = 0x1002;
24
25 public final static int SO_KEEPALIVE = 0x0008;
26
27 public final static int SO_OOBINLINE = 0x1003;

2、public final static int TCP_NODELAY = 0x0001;

要理解这个参数,首先要理解Nagle算法,下面先说说这个Nagle算法

2.1 Nagle算法产生的背景    当网络传输中存在大量小包传输时,会严重影响传输效率。比如一个包,包头40字节,而真正的内容只有一个字节或者几个字节(典型的有Telnet),这样的传输效率是十分低下的。Nagle算法要解决的就是这种低效率的传输问题。

2.2 Nagle算法的原理    用通俗的话来说就是,把小包要发送的字节先缓存,当到达一定的阀值的时候再一次性传输。具体算法(伪代码)如下:
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
其中MSS为maximum segment size的缩写,是TCP头部的一个字段,表示一个TCP段最大的数据承载量。

2.3 Nagle算法的问题   在传输大文件的时候,如果使用这个算法,那么会出现明显的延迟现象,因此,在这种情况下,最好是关闭这个算法。

知道了Nagle算法,就知道了TCP_NODELAY这个参数的意义了,如果这个参数被设置为True,那么就是关闭Nagle算法,实现无延迟传输,如果设置为false,则是打开这个算法,会对发送的数据进行缓存。

3、public final static int SO_BINDADDR = 0x000F;   获取绑定套接字的本地地址(不能仅将此选项“设置”为“得到”,因为套接字是在创建时绑定的,所以本地绑定的地址不可更改)。

4、public final static int SO_REUSEADDR = 0x04;

   这个参数表示套接字对端口是否可重用。   这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息,指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时 SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不可能。

一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组还是唯一确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使用 SO_REUSEADDR 选项。

5、public final static int SO_BROADCAST = 0x0020;

这个参数选项用来控制广播,目前只有在DatagramSocket里支持。

6、public final static int IP_MULTICAST_IF = 0x10;

用来控制多播的参数选项,目前只有在MulticastSocket里支持

在MulticastSocket的源代码里有设置多播的方法:

 public void setInterface(InetAddress inf) throws SocketException {
    if (isClosed()) {
        throw new SocketException("Socket is closed");
    }
    checkAddress(inf, "setInterface");
    synchronized (infLock) {
        getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
        infAddress = inf;
    }
    }

7、public final static int IP_MULTICAST_IF2 = 0x1f;

这个字段的效果和上面的是一样的,只是扩展支持IPV6

8、public final static int IP_MULTICAST_LOOP = 0x12;

用来设置本地回环接口的多播特性,在MulticastSocket源代码中有相关方法:

/**
     * Disable/Enable local loopback of multicast datagrams
     * The option is used by the platform‘s networking code as a hint
     * for setting whether multicast data will be looped back to
     * the local socket.
     *
     * <p>Because this option is a hint, applications that want to
     * verify what loopback mode is set to should call
     * {@link #getLoopbackMode()}
     * @param disable <code>true</code> to disable the LoopbackMode
     * @throws SocketException if an error occurs while setting the value
     * @since 1.4
     * @see #getLoopbackMode
     */
    public void setLoopbackMode(boolean disable) throws SocketException {
    getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
    }

9、public final static int IP_TOS = 0x3;

这个参数是用来控制IP头中的TOS字段的,是用来控制和优化IP包的路径的,在Socket源代码里有一个设置的方法:

/**
     * Sets traffic class or type-of-service octet in the IP
     * header for packets sent from this Socket.
     * As the underlying network implementation may ignore this
     * value applications should consider it a hint.
     *
     * <P> The tc <B>must</B> be in the range <code> 0 <= tc <=
     * 255</code> or an IllegalArgumentException will be thrown.
     * <p>Notes:
     * <p> For Internet Protocol v4 the value consists of an octet
     * with precedence and TOS fields as detailed in RFC 1349. The
     * TOS field is bitset created by bitwise-or‘ing values such
     * the following :-
     * <p>
     * <UL>
     * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
     * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
     * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
     * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
     * </UL>
     * The last low order bit is always ignored as this
     * corresponds to the MBZ (must be zero) bit.
     * <p>
     * Setting bits in the precedence field may result in a
     * SocketException indicating that the operation is not
     * permitted.
     * <p>
     * As RFC 1122 section 4.2.4.2 indicates, a compliant TCP
     * implementation should, but is not required to, let application
     * change the TOS field during the lifetime of a connection.
     * So whether the type-of-service field can be changed after the
     * TCP connection has been established depends on the implementation
     * in the underlying platform. Applications should not assume that
     * they can change the TOS field after the connection.
     * <p>
     * For Internet Protocol v6 <code>tc</code> is the value that
     * would be placed into the sin6_flowinfo field of the IP header.
     *
     * @param tc        an <code>int</code> value for the bitset.
     * @throws SocketException if there is an error setting the
     * traffic class or type-of-service
     * @since 1.4
     * @see #getTrafficClass
     */
    public void setTrafficClass(int tc) throws SocketException {
    if (tc < 0 || tc > 255)
        throw new IllegalArgumentException("tc is not in range 0 -- 255");

    if (isClosed())
        throw new SocketException("Socket is closed");
        getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
    }

从源代码的注释看,TOS设置了是否生效,和底层的操作系统的实现有关。应用程序无法保证TOS的变更会对socket连接产生影响。个人认为,TOS在一般情况下用不到。

10、public final static int SO_LINGER = 0x0080;

先看Socket源代码:

/**
     * Enable/disable 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 JDK1.1
     * @see #getSoLinger()
     */
    public void setSoLinger(boolean on, int linger) throws SocketException {
    if (isClosed())
        throw new SocketException("Socket is closed");
    if (!on) {
        getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on));
    } else {
        if (linger < 0) {
        throw new IllegalArgumentException("invalid value for SO_LINGER");
        }
            if (linger > 65535)
                linger = 65535;
        getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
    }
    }

这个字段对Socket的close方法产生影响,当这个字段设置为false时,close会立即执行并返回,如果这时仍然有未被送出的数据包,那么这些数据包将被丢弃。如果设置为True时,有一个延迟时间可以设置。这个延迟时间就是close真正执行所有等待的时间,最大为65535。

11、public final static int SO_TIMEOUT = 0x1006;

/**
     *  Enable/disable SO_TIMEOUT with the specified timeout, in
     *  milliseconds.  With this option set to a non-zero timeout,
     *  a read() call on the InputStream associated with this Socket
     *  will block for only this amount of time.  If the timeout expires,
     *  a <B>java.net.SocketTimeoutException</B> is raised, though the
     *  Socket is still valid. The option <B>must</B> be enabled
     *  prior to entering the blocking operation to have effect. The
     *  timeout must be > 0.
     *  A timeout of zero is interpreted as an infinite timeout.
     * @param timeout the specified timeout, in milliseconds.
     * @exception SocketException if there is an error
     * in the underlying protocol, such as a TCP error.
     * @since   JDK 1.1
     * @see #getSoTimeout()
     */
    public synchronized void setSoTimeout(int timeout) throws SocketException {
    if (isClosed())
        throw new SocketException("Socket is closed");
    if (timeout < 0)
      throw new IllegalArgumentException("timeout can‘t be negative");

    getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
    }

这个参数用来控制客户端读取socket数据的超时时间,如果timeout设置为0,那么就一直阻塞,否则阻塞直到超时后直接抛超时异常。

12、public final static int SO_SNDBUF = 0x1001;

在默认情况下,输出流的发送缓冲区是8096个字节(8K)。这个值是Java所建议的输出缓冲区的大小。如果这个默认值不能满足要求,可以用setSendBufferSize方法来重新设置缓冲区的大小。

13、public final static int SO_RCVBUF = 0x1002;

在默认情况下,输入流的接收缓冲区是8096个字节(8K)。这个值是Java所建议的输入缓冲区的大小。如果这个默认值不能满足要求,可以用setReceiveBufferSize方法来重新设置缓冲区的大小。

14、public final static int SO_KEEPALIVE = 0x0008;

如果将这个参数这是为True,客户端每隔一段时间(一般不少于2小时)就像服务器发送一个试探性的数据包,服务器一般会有三种回应:

1、服务器正常回一个ACK,这表明远程服务器一切OK,那么客户端不会关闭连接,而是再下一个2小时后再发个试探包。

2、服务器返回一个RST,这表明远程服务器挂了,这时候客户端会关闭连接。

3、如果服务器未响应这个数据包,在大约11分钟后,客户端Socket再发送一个数据包,如果在12分钟内,服务器还没响应,那么客户端Socket将关闭。

15、public final static int SO_OOBINLINE = 0x1003;

如果这个Socket选项打开,可以通过Socket类的sendUrgentData方法向服务器发送一个单字节的数据。这个单字节数据并不经过输出缓冲区,而是立即发出。虽然在客户端并不是使用OutputStream向服务器发送数据,但在服务端程序中这个单字节的数据是和其它的普通数据混在一起的。因此,在服务端程序中并不知道由客户端发过来的数据是由OutputStream还是由sendUrgentData发过来的。

时间: 2024-10-09 15:56:11

java socket 的参数选项解读的相关文章

java socket 的参数选项解读(转)

java socket中有很多参数可以选择,这篇博客的目的是沉淀出这些参数的语义和用法,供自己以后查阅. 1.java socket参数选项总览 在JDK1.6中有如下参数选项: 1 public final static int TCP_NODELAY = 0x0001; 2 3 public final static int SO_BINDADDR = 0x000F; 4 5 public final static int SO_REUSEADDR = 0x04; 6 7 public fi

Java 6 JVM参数选项大全(中文版)

原文来自: http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm 本文是基于最新的SUN官方文档Java SE 6 Hotspot VM Options 编写的译文.主要介绍JVM中的非稳态选项及其使用说明. 为了让读者明白每个选项的含义,作者在原文基础上补充了大量的资料.希望这份文档,对正在研究JVM参数的朋友有帮助! 非稳态选项使用说明 -XX:+<option> 启用选项 -XX:-<option> 不

网络编程中的Socket详解---Socket重要参数详解

Java Socket的api可能很多人会用,但是Java Socket的参数可能很多人都不知道用来干嘛的,甚至都不知道有这些参数. backlog 用于ServerSocket,配置ServerSocket的最大客户端等待队列.等待队列的意思,先看下面代码 public class Main { public static void main(String[] args) throws Exception { int port = 8999; int backlog = 2; ServerSo

java socket 参数

Java socket参数选项: TCP_NODELAY:  表示立即发送数据 SO_RESUSEADDR:  表示是否允许重用socket所绑定的本地地址 SO_TIMEOUT :  表示接收数据时的等待超时时间 . 单位为毫秒,默认值为0 , 表示永远等待. SO_LINGER:  表示当执行 socket的close方法的时候,是否立即关闭底层的socket . 这个单位是秒. SO_SNFBUF:  发送数据的缓冲区大小 SO_RCVBUF:  接收数据的缓冲区大小 SO_KEEPLIV

Java - Java 命令行简介: 选项, 属性, 参数

概述 简单介绍一下 java 命令行相关的参数及属性 1. java 命令行 基本 命令 > java <mainClass> 描述 执行 Java 类 需要准备好编译完成的 mainClass 然后 命令 > java -X<options> -XX<options> -D<properties> <mainClass> [arg0] [arg1]... 怎么感觉, 东西一下多了好多, 有点懵逼了 没事, 慢慢来 这些东西, 大概分

java Socket用法详解(转)

在客户/服务器通信模式中, 客户端需要主动创建与服务器连接的 Socket(套接字), 服务器端收到了客户端的连接请求, 也会创建与客户连接的 Socket. Socket可看做是通信连接两端的收发器, 服务器与客户端都通过 Socket 来收发数据. 这篇文章首先介绍Socket类的各个构造方法, 以及成员方法的用法, 接着介绍 Socket的一些选项的作用, 这些选项可控制客户建立与服务器的连接, 以及接收和发送数据的行为. 一. 构造Socket Socket的构造方法有以下几种重载形式:

java Socket(详解)转载

在客户/服务器通信模式中, 客户端需要主动创建与服务器连接的 Socket(套接字), 服务器端收到了客户端的连接请求, 也会创建与客户连接的 Socket. Socket可看做是通信连接两端的收发器, 服务器与客户端都通过 Socket 来收发数据. 这篇文章首先介绍Socket类的各个构造方法, 以及成员方法的用法, 接着介绍 Socket的一些选项的作用, 这些选项可控制客户建立与服务器的连接, 以及接收和发送数据的行为. 一. 构造Socket Socket的构造方法有以下几种重载形式:

Java基础10:全面解读Java异常

Java基础10:全面解读Java异常 为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位,作用. 在没有异常机制的时候我们是这样处理的:通过函数的返回值来判断是否发生了异常(这个返回值通常是已经约定好了的),调用该函数的程序负责检查并且分析返回值.虽然可以解决异常问题,但是这样做存在几个缺陷: 1. 容易混淆.如果约定返回值为-11111时表示出现异常,那么当程序最后的计算结果真的为-1111

java socket 基于UDP/IP 协议

Java  socket 基于UDP/IP协议应用 服务器端:  1.创建DatagramSocket,指定端口号 2.创建DatagramPacket 3.接收客户端发送的数据 4.读取数据 客户端: 1.  定义发送信息: 服务器的IP 端口号  发送的内容 2.  创建DatagramPacket,包含将要发送的信息 3.  创建DatagramSocket 4.  发送数据 服务器端 import java.io.IOException; import java.net.Datagram