紧急数据传输
已经建立连接的C/S两端中,当某一端发生了比较重要且紧急的事情时,需要在不建立新连接,即在当前连接的基础上将该信息迅速通知到对端,但是在TCP数据传输中肯定要遵循先写入缓冲区的数据先被发送的规则,除非你的数据有某种优先权!
对,上面所说的优先权就是TCP数据传输中的紧急模式.这类似于其他传输层协议中的带外数据(经加速数据)的说法,大部分传输层协议都有解决紧急数据传输的实现,除过UDP协议中没有带外数据的实现方法.
TCP紧急模式
TCP紧急模式设置特别简单.举个例子就会懂,假设有一组已经在套接字缓冲区中排队将要发送到对端的数据(1,2,3,4,5…N),在该缓冲区中要发送的数据末尾设置OOB标记作为缓冲区中最后一个字节,通常存在一个紧急指针指向OOB标记字节的下一个字节.而OOB标记字节的前一个字节就会作为紧急数据随同其之前一系列普通数据发送到对端.程序中设置的话:
send(fd,“a”,1,MSG_OOB);
以上意思就是将a设置成紧急字节发送到对端.
紧急数据的发送
对于紧急数据的发送,要在TCP数据包首部设置URG标记和紧急指针,以上是可以找到相应的位置,URG 标记是用来让
TCP检查紧急指针紧急偏移的,没有的话,是不会检查的
,要是有的话,就通过检查紧急指针偏移量来定位紧急数据在TCP 数据部分所处的位置,上面也已经陈述了紧急指针的偏移的位置所在了,在这里不赘述了.
几种特殊情况说明
然而有的时候设置了URG标志位,实际的紧急数据却不一定随同发出,这种情况就是发送端要是因为流量控制而停止发送数据
即该端发送缓冲区已满,那就真没法在添什么紧急数据了
,而此时紧急通知肯定会到对端,但是紧急数据不会到达.
不是规定了一次只能设置一个字节的紧急数据吗?肯定就有人尝试一次设置多个字节的紧急数据:send(fd,“abc”,3,MSG_OOB);
说明一下这种情况吧,要是一次性设置多个字节的紧急数据,只有最后一个字节会被认为是真正的紧急数据,之前的字节数据会被丢弃.不信可以试试.
- 发送端
- 接收端
以上就是大概示例程序代码及运行结果.综上来看,确实没错.
紧急数据的接收
由于发送端通常发送多个设置了URG位且紧急指针指向同一个数据段的分节,当收到一个含有URG的分节时,接收端检查紧急指针,确定是否指向新的紧急数据(
多个到选最先到的那一个,因为急呀!!!
)要是的话,让内核发送SIG_URG信号通知应用进程接收紧急数据.当然应用进程就需要有设置相应接收信号的接口.
进程通过调用fcntl或者ioctl的file control函数为发送端套接字建立了属主,并且改进程有相应的接收内核紧急数据信号的处理函数.
当然,以上是针对紧急数据的一般处理方式,肯定还有特殊处理的状况了,因为从发送端到达的紧急数据可能就处在套接字缓冲区中(即在线留存
),也可能就是存在一个单子节缓冲区中.一般默认为单子节缓冲区.我们可以对紧急数据进行一些特殊处理,就可以让他在线留存,开启SO_OOBINLINE选项,使得紧急数据留在套接字缓冲区中,应用进程通过检查带外标记获取带外数据,这是就不需要处理来自内核的信号处理函数了.
紧急数据接收的一些错误
- 如果接收进程指定MSG_OOB标记请求读入带外数据时,但是发送端尚未发送任何带外数据;或者是接收进程多次读入同一个紧急数据;图过已经开启了SO_OOBINLINE选项,却通过指定MSG_OOB来读取带外数据,这些都会在读操作时返回EINVAL错误.
- 之前已经说了,有的TCP分节即使设置URG标记位了,但是实际的带外数据因为流量控制而不能同时传输过来,这种情况接收端在读紧急数据操作时,会返回EWOULDBLOCK.
总结
- 为什么将紧急字节来放在TCP首部紧急指针那个位置,那不是更加方便吗?没错,方便是方便,但是有丢失的风险,因为TCP数据包在ip层可能被拆包,成为多个数据段.一个包含紧急数据的数据包被拆成两个数据包,那么这两个包有的tcp头部有相同的紧急指针(和UGR).如果将紧急数据直接放在紧急指针的内存处,那么将多出一个紧急数据!所以,不该将紧急数据放在TCP头部.同时,在拆包后,对端将收到两个包,第一个包到达的时候就知道了UGR和紧急指针.如果紧急指针所指的位置已在该包的数据段中,那么紧急数据就到达了.否则,要等到第二个包到达的时候,才能去得到紧急数据.总之,当收到tcp包的数据段已经被设置紧急URG,那么说明进入紧急状态,这时系统会通知进程信号MIGURG.之于紧急数据什么时候到达.那么要等到紧急指针所指的数据流的到达。
- 发送端发送紧急数据后,接收端通过内核发送SIGURG信号或者select调用通知接收端进程发送端进入紧急模式这一信息.并使其进入特殊的接收模式接收带外数据和普通数据.
- 带外字节的位置,即它相对于来自发送端的其他数据的发送位置带外标记.
- 带外字节是任何八位值.
- 对于TCP的紧急模式,URG标记是通知,紧急指针是带外标记,紧急字节是实际紧急数据.
- 每个连接只有一个TCP紧急指针,一个紧急指针标记,一个单字节的带外缓冲区.新到达标记覆写接收进程尚未碰到的任何先前的标记.如果带外数据是在线读入的,那么当新的带外数据到达时,向前的带外数据并未丢失,只是带外标记因被新的取代而丢失了.