Socket的OOBINLINE选项是用于处理TCP紧急数据的一个设置。TCP紧急数据通常指的是那些需要优先处理的数据,例如某些控制信息或关键数据。

OOB(Out-of-Band)表示带外数据,OOBInline是一个Socket选项,用于控制是否将接收到的带外数据(Out-of-Band data)与普通数据混合在一起。如果设置了OOBInline为true,那么带外数据将与普通数据混合在一起,可以通过相应的方式进行处理。如果设置为false,则带外数据将单独处理。默认情况下,OOBInline为false。

当OOBINLINE选项被设置为true时,表示支持发送一个字节的TCP紧急数据。这可以通过Socket类的sendUrgentData(int data)方法来实现。在这种情况下,接收方会把接收到的紧急数据与普通数据放在同样的队列中,从而可以通过套接字输入流来接收这些紧急数据。

然而,如果OOBINLINE选项被设置为false(这是其默认值),那么当接收方收到紧急数据时,它不会进行任何特殊处理,而是直接将其丢弃。这意味着,如果用户希望接收紧急数据,他们必须显式地将OOBINLINE选项设置为true。

总的来说,OOBINLINE选项为Socket提供了一种处理紧急数据的机制,允许开发者根据实际需求来选择是否接收和如何处理这些紧急数据。

在JAVA中可以通过下面的api来开启OOBINLINE:

public void setOOBInline(boolean on) throws SocketException

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

下面是sendUrgentData方法的声明:

public void sendUrgentData(int data) throws IOException

虽然sendUrgentData的参数data是int类型,但只有这个int类型的低字节被发送,其它的三个字节被忽略。

下面的代码演示了如何使用SO_OOBINLINE选项来发送单字节紧急数据。

Socket服务端代码如下:

package com.morris.socket;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;/** * Socket服务端,演示OOBInline选项的效果 */public class OobInlineServerDemo {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8899);System.out.println("server is listening at 8899");while (true) {Socket socket = serverSocket.accept();// 允许带外数据(Out-of-Band data)与普通数据混合在一起//socket.setOOBInline(true);BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));String line;while (null != (line = bufferedReader.readLine())) {System.out.println(line);}socket.close();}}}

Socket客户端代码如下:

package com.morris.socket;import java.io.IOException;import java.io.PrintWriter;import java.net.Socket;/** * Socket客户端,演示OOBInline选项的效果 */public class OobInlineClientDemo {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 8899);PrintWriter printWriter = new PrintWriter(socket.getOutputStream());printWriter.write('C'); // 向服务器发送字符"C"printWriter.write("hello world");// 客户端发送紧急数据socket.sendUrgentData(65); // 向服务器发送字符"A"socket.sendUrgentData(322); // 向服务器发送字符"B"printWriter.flush();socket.close();}}

先运行服务端再运行客户端,服务端收到的数据如下:

server is listening at 8899ABChello world

从接收到的数据可以发现一个问题,在客户端中先后向服务器发送了Chello worldAB。而在服务端接收到的数据顺序是ABChello world。这种现象说明使用sendUrgentData方法发送数据后,系统会立即将这些数据发送出去;而使用write发送数据,必须要使用flush方法才会真正发送数据。

服务端tcpdump抓到的包如下:

11:32:46.153914 IP 127.0.0.1.42752 > 127.0.0.1.8899: Flags [P.U], seq 1:2, ack 1, win 512, urg 1, options [nop,nop,TS val 532795477 ecr 532795476], length 111:32:46.153977 IP 127.0.0.1.42752 > 127.0.0.1.8899: Flags [P.U], seq 2:3, ack 1, win 512, urg 1, options [nop,nop,TS val 532795477 ecr 532795477], length 1

可见包中的标志位有U。

然后将服务端下面的代码注释掉,关闭OOBInline选项:

//socket.setOOBInline(true);

先运行服务端再运行客户端,服务端收到的数据如下:

server is listening at 8899Chello world

可以看到服务端只收到了普通数据,收不到紧急数据了。

TCP的紧急指针,一般都不建议使用,而且不同的TCP/IP实现,也不同,一般说如果你有紧急数据宁愿再建立一个新的TCP/IP连接发送数据,让对方紧急处理。