1 概述
喜多传输层由带外数据(out-of-band data)的概念,它有时也称为经加速数据(expedited data)。其想法是一个连接的某端发生了重要的事情,而且该端希望迅速通告其对端。这里“迅速”意味着这种通知应该在已经排队等待发送的任何“普通”(有时称为“带内”)数据之前发送。也就是说,带外数据被认为具有比普通数据更高的优先级。带外数据并不要求在客户和服务器之间再使用一个连接,而是被映射到已有的连接中。
2 TCP带外数据
TCP并没有带外数据,而是提供了紧急模式(urgent mode)。假设一个进程已经往一个TCP套接字写出N字节数据,而且TCP把这些数据排队在该套接字的发送缓冲区中,等着发送到对端。图1-1展示了这样的套接字发送缓冲区,并标记了从1到N的数据字节。
图1-1 含有待发送数据的套接字发送缓冲区
该进程接着以MSG_OOB标志调用send函数写出一个含有ASCII字符a的单字节带外数据:
send( fd, " a ", 1, MSG_OOB );
TCP把这个数据放置在该套接字发送缓冲区的下一个可用位置,并把该连接的TCP紧急指针(urgent pointer)设置成再下一个可用位置。图1-2展示了此时的套接字发送缓冲区,并把带外字节标记为“OOB”。
图1-2 应用进程写入1字节带外数据后的套接字发送缓冲区
3 sockatmask函数
每当收到一个带外数据时,就有一个与之关联的带外标记(out-of-band mark)。这是发送进程发送带外字节时该字节在发送端普通数据流中的位置。在套接字读入期间,接收进程通过调用sockatmask函数确定是否处于带外标记。
/* Determine wheter socket is at a out-of-band mark. */extern int sockatmark (int __fd) __THROW;
带外标记有以下两个特性。
-
带外标记总是指向普通数据最后一个字节紧后的位置。这意味着,如果带外数据在线接收,那么如果下一个待读入的字节是使用MSG_OOB标识送的,sockatmark就返回真。而如果SO_OOBINLINE套接字选项没有开启,那么,若下一个待读入的字节是跟在带外数据后发送的第一个字节,sockatmark就返回真。
-
读操作总是停在带外标记上。也就是说,如果在套接字接收缓冲区中有100个字节,不过在带外标记之前只有5个字节,而进程执行一个请求100个字节的read调用,那么返回的是带外标记之前的5个字节。这种在带外标记上强制停止读操作的做法使得进程能够调用sockatmark确定缓冲区指针是否处于带外标记。
-
即使因为流量控制而停止发送数据了,TCP仍然发送带外数据的通知(即它的紧急指针)。
-
在带外数据到达之前,接收进程可能被通知说发送进程已经发送了带外数据(使用SIGURG信号或通过select)。如果接收进程接着指定MSG_OOB调用recv,而带外数据却尚未到达,recv将返回EWOULDBLOCK错误。
-
如果在接收进程读入某个现有带外数据之前有新的带外数据到达,先前的标记就会丢失。