8:带外数据

- 带外数据
一个连接的某端发生了某事,希望迅速通告其对端
带外数据被认为具有比普通数据更高的优先级
后续只关注TCP的带外数据模型

TCP带外数据

TCP提供了紧急模式
send(fd, "a", 1, MSG_OOB);

在这里插入图片描述

TCP紧急指针对应一个TCP序列号,是用MSG_OOB标志写的最后一个数据字节对应的序列号加1
给定上述TCP套接字的发送缓冲区状态,
发送端TCP将为待发送的下一分节在TCP首部设置URG标志,并把紧急偏移字段设为指向带外字节后的字节.
OOB字节是否发送取决于在套接字发送缓冲区先于它的字节数,TCP准备发给对端的分节大小,对端通告的当前窗口.
TCP首部的16位值称为紧急指针,它需加上同一个首部中的序列号字段才能获得32位的紧急指针.
只在同一首部中称为URG标志的位已经设置的前提下,TCP才检查紧急偏移.

TCP首部指出发送端已经进入紧急模式.
但由紧急指针所指的实际数据字节却不一定随同送出.
即使TCP因流量控制而暂停发送数据,紧急通知照样不伴随任何数据地发送.

- 对接收端
1.当收到一个设置了URG标志的分节时,
接收端TCP检查紧急指针
确定它是否指向新的带外数据
也即判断本分节是不是首个到达的引用从发送端到接收端的数据流中特定字节的紧急模式分节.
发送端TCP往往发多个含URG标志且紧急指针指向同一个数据字节的分节
这些分节中只有第一个到达的会导致通知接收进程有新的带外数据到达.
2.当有新的紧急指针到达时,
接收进程将被通知到.
首先,
内核给接收套接字的属主进程发SIGURG信号
前提是接收进程[或其他进程]曾调fcntl或ioctl为此套接字建立了属主
且该属主进程已为此信号建立了信号处理函数
其次,如接收进程阻塞在select调用,以等待此套接字描述符出现一个异常条件,
select调用就返回.

只有一个OOB标记,
如新的OOB字节在旧的OOB字节被读取前就到达,旧的OOB字节会被丢弃.
3.当由紧急指针指向的实际数据字节到达接收端TCP时,
该数据字节既可能被拉出带外,
也可能被留在带内

SO_OOBINLINE禁止下,
对接收端套接字,该数据字节并不放入套接字接收缓冲区.
而是放入该连接的一个独立的单字节带外缓冲区.
接收进程从此单字节缓冲区读入数据的唯一办法是指定MSG_OOB调recv, recvfrom, recvmsg
如新的OOB字节在旧的OOB字节被读取前就到达,旧的OOB字节被丢弃.
SO_OOBINLINE开启下,
有TCP紧急指针指向的实际数据字节将被留在通常的套接字接收缓冲区中
此时,
接收进程不能指定MSG_OOB标志读入该数据字节
相反,接收进程通过检查该连接的带外标记以获悉何时访问到这个数据字节.
	
发生一些错误是可能的
1.如接收进程请求读入带外数据[指定MSG_OOB]
但对端尚未发送任何带外数据
读入操作将返回EINVAL
2.在接收进程已被告知对端发送了一个带外字节[通过SIGURG或select]的前提下,
如接收进程试图读入该字节,但该字节尚未到达,读入操作将返回EWOULDBLOCK.
接收进程此时能做的仅是从套接字接收缓冲区读入数据
以便在该缓冲区中腾出空间
继而允许对端TCP发出那个带外字节
3.如接收进程试图多次读入同一个带外字节
读入操作将返回EINVAL
4.如接收进程已经开启了SO_OOBINLINE
后来试图通过MSG_OOB读带外数据,读入将返回EINVAL

sockatmark

每当收到一个带外数据时,就有一个与之关联的带外标记
这是发送进程发送带外字节时该字节在发送端普通数据流中的位置
从套接字读入期间,通过调sockatmark确定是否处于带外标记
int sockatmark(int sockfd);
- 带外标记总是指向普通数据最后一个字节紧后的位置
如带外数据在线接收,则如下一待读入字节是用MSG_OOB标志发送的.
sockatmark就返回真
如SO_OOBINLINE没开启,若下一个待读入的字节是跟在带外数据后发送的第一个字节,sockatmark就返回真

- 读操作总是停在带外标记上
也即,
如在套接字接收缓冲区有100字节
在带外标记前有5字节
进程执行一个请求100字节的read调用
则返回的是带外标记前的5字节
在带外标记上强制停止读操作的做法使得进程能调sockatmark确定缓冲区指针是否处于带外标记

小结

带外数据向接收端传达三个信息
1.发送端进入紧急模式
URG标志
发送进程发送带外字节后由发送端TCP立即发送
2.带外字节的位置
带外标记[紧急指针]
3.带外字节的实际值

相关问题:
1.每个TCP连接只有一个紧急指针
2.每个连接只有一个带外标记
3.每个连接只有一个单字节带外缓冲区[数据非在线读入时才被考虑]

TCP没有真正的带外数据,不过提供紧急模式,紧急指针
一旦发送端进入紧急模式
紧急指针就出现在发到对端的分节中的TCP首部
连接的对端收取该指针,是在告知接收进程发送端已经进入紧急模式.且该指针指向紧急数据的最后一个字节.
数据的发送仍受TCP正常的流量控制支配.
发送进程通过指定MSG_OOB调send让发送端进入紧急模式
该调用中最后一个字节被认为是带外字节
接收端TCP收到新的紧急指针后,或通过发SIGURG信息,或通过由select返回套接字的指示.
让接收进程得以通知.
默认下,接收端TCP把带外字节从普通数据流取出存放到自己的单字节带外缓冲区.
供接收进程通过指定MSG_OOB调recv获取.
不管接收进行按将带外字节放在普通数据流还是额外单字节缓冲区中进行接收,
套接字在数据流中都维护一个带外标记,且不允许单个读取操作读过此标记.
调sockatmark可获知是否已到达此标记.

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/110483480
今日推荐