blog原文地址:http://blog.csdn.net/ordeder/article/details/43243425
本文系读书笔记,主要参考材料:http://wenku.baidu.com/view/f04a4dff9e31433239689341.html
头部标志: URG位,紧急指针。
数据包中:一个紧急指针只指向一个字节的带外数据的后已字节位置。紧急数据时插在正常数据流中进行传输。紧急指针用于指出带外数据字节在正常字节流中的位置。
问题:为何不直接将一个字节的紧急数据放在紧急指针哪里呢?
答:因为TCP数据包在ip层可能被拆包,成为多个数据段。一个包含紧急数据的数据包被拆成两个数据包,那么这两个包有的tcp头部有相同的紧急指针(和UGR)。如果将紧急数据直接放在紧急指针的内存处,那么将多出一个紧急数据!所以,不该将紧急数据放在TCP头部。
同时,在拆包后,对端将收到两个包,第一个包到达的时候就知道了UGR和紧急指针。如果紧急指针所指的位置已在该包的数据段中,那么紧急数据就到达了。否则,要等到第二个包到达的时候,才能去得到紧急数据。总之,当收到tcp包的数据段已经被设置紧急URG,那么说明进入紧急状态,这时系统会通知进程信号MIGURG。之于紧急数据什么时候到达,那么要等到紧急指针所指的数据流的到达。
接口:
send(sockfd,"X", 1, MSG_OOB);
设当前的sockfd的发送缓冲区为:
Send_Buff: 1 2 3 4 5 6 7 8
调用send(sockfd,"X", 1,MSG_OOB);发出紧急数据X,那么发送缓冲区为:
Send_Buff: 1 2 3 4 5 6 7 8 X
Tcp->IP:
情况1: 发送窗口大于等于9,那么紧急数据刚好在这次被发出,tcp包头部URG被置位,紧急指针值为10(seq)。
情况2:发送窗口小于9,那么由流式机制可知,先要将X前面的字节发出。假设窗口为6,第一个tcp包发出,URG被置位,紧急指针值为10(seq)。数据部分为:1 2 3 4 5 6
第二个tcp包发出,URG被置位,紧急指针值为10(seq)。数据部分为:7 8 X。
对端收到第一个tcp包时,检测URG可知进入了紧急状态,但是有当前的seq和接受的数据量即之和小于紧急指针的值,那么说明紧急数据还未到来。下一个包到来时,判定紧急指针与前一包是相同的值,说明是同一个紧急指针,同理通过判定指针和当前接受的数据量来确定紧急数据是否到来。
假设当前的紧急指针和前一个包的紧急指针不是一个值,那么说明有新的紧急数据到来了。
总结:URG指定程序进入紧急状态,紧急数据的发出还是在对端的发送缓冲中依据流形式发出。所以可能紧急数据要推迟到来。
奇葩的:send(sockfd,"90X", 1,MSG_OOB);
发送缓冲区为:1 2 3 4 5 6 7 8 9 0 X
由于紧急指针只能标识一个字节的数据,所以只有X为紧急数据,90将被视为正常数据。
1 接收端接受到带有URG标志的数据段时:a、判断当前的紧急指针与先前紧急指针(之前数据段)是否相同。相同则是因为tcp数据包可能被分成多个数据段,或者发送端在发出紧急数据前还有额外的正常数据发送。不同,则说明进入新的紧急状态,从而通知用户进程(sigurg),即:新的第一个紧急指针才会通知用户进程。
2 用户进程中,SIGURG信号被传递给套接字的宿主。套接字的宿主设置有:
fcntl(sockfd,F_SETOWN, getpid());
3 紧急指针所指向的带外数据到达接收端后,带外数据被放置的位置分为两种情况:
3.1 套接字选项SO_OOBINLINE未被设置(默认),这一字节的带外数据被放置在套接字带外数据缓冲区中,这个缓冲区大小为一个字节。进程读取方法:
recv(sockfd,&ch,1,MSG_OOB);
在紧急状态下,上述调用对于:带外数据仍未到达,函数返回回EWOULDFBLOCK。 在非紧急状态下,调用上述函数,将返回EINVAL。
3.2 套接字选项SO_OOBINLINE被设置,则由紧急指针所指的,代表带外数据的那个字节将会被放在正常套接字缓冲区中的最左边。在这种情况下,进程不能指定MSG_OOB 来读取这个一个字节的带外数据。这种方式在读取数据前需要提前判定下一字节是否为带外数据。
ioctl (fd,SIOCATMARK,&flag);
if (flag)
read(sockfd,&ch,1);
SO_OOBINLINE模式原理:当带外数据到达接受缓冲区后,套接字有特殊字段记录该紧急数据在接受缓冲区中与缓冲区头部的偏移量。当应用程序读取前面的正常数据时,该偏移量将作出修正。当偏移量为0时,表示即前被读取的字节是带外数据,此时套接字状态字段的SIOCATMARK置1。
1. 紧急数据在发送和接受时没有特权,紧急数据时插入到普通的数据中进行流式发送的。在TCP层面(非应用层),发送端缓冲区中,只有先把紧急数据之前的普通数据发送后才能发送紧急数据。同时,在接收端只有接收到紧急数据之前的正常数据流之后,但接接受这个字节的带外数据。
2. URG标志紧急状态,紧急数据是否正式到达需要依据紧急指针来判定(该指针指向的位置的数据如果还未到来,说明这个紧急数据还未被接收)。
3. 在想发送缓冲区放入紧急数据后,在该紧急数据还未被发送之前(原因见1),发送的正常数据段的tcp头部就被设置了URG标记和紧急指针(就如2)。所以接受端可能会连续接受到几个tcp包,他们的包头部URG被设置,并且紧急指针都指向同一个位置(原因有1)。对接受段而言,仅接收到的第一个URG(相同紧急指针)的数据包时,通过SIGURG通知应用程序进入紧急状态(做好接受准备)。另外,应用程序可以通过select函数,在exception参数设置要监听的套接字的紧急情况,从而实现紧急数据的主动监听。实例如下:
· rc = select( ws + 1, &rs, NULL, &xs,NULL );
· if ( rc > 0&& FD_ISSET( ws, &rs ) )
· break;
· if ( rc > 0&& FD_ISSET( ws, &xs ) ) {
· t = recv( ws, x, sizeof( x ), MSG_OOB );
原文地址:http://blog.csdn.net/ordeder/article/details/43243425