TCP带外数据OOB
来源:互联网 发布:中国网络日报。 编辑:程序博客网 时间:2024/06/03 02:43
原文地址:http://blog.csdn.net/ty_laurel/article/details/52164669
传输层协议使用带外数据(out-of-band,OOB)来发送一些重要的数据,如果通信一方有重要的数据需要通知对方时,协议能够将这些数据快速地发送到对方.为了发送这些数据,协议一般不使用与普通数据相同的通道,而是使用另外的通道实现.
OOB数据(TCP)介绍
带外数据即就是优先数据,linux系统的套接字机制支持低层协议发送和接受带外数据.但是TCP协议没有真正意义上的带外数据.为了发送重要协议,TCP提供了一种称为紧急模式(urgent mode)的机制。TCP在报文头中设置URG位,表示进入紧急模式.接收方可以对紧急模式采取特殊的处理。
tcp报文格式
很容易看出来,这种方式数据不容易被阻塞,可以通过在我们的服务器端程序里面捕捉SIGURG信号来及时接受数据或者使用带OOB标志的recv函数来接受.使用send和recv函数时,可以指定最后一个参数flags为MSG_OOB来发送接收带外数据。
send(...,MSG_OOB,); recv(...,MSG_OOB,);
- 1
- 2
OOB数据特点
1.OOB数据每次只能是一个字符
2.普通数据使用一般方式接收与发送,OOB数据使用MSG_OOB接收与发送
3.一个数据使用MSG_OOB,则最后一个字符是OOB数据,其他的是非OOB数据
4.OOB数据是优先数据。优先体现在什么地方?
在我看来OOB数据优先体现在同一次发送数据(包含普通数据和OOB数据)时,OOB数据会优先于普通数据到达目标端。下边有实例可以认证这一点。
带外数据发送过程:和普通数据发送过程一样,只是在数据字符串最后一个字符处设置一个标记,目标端接收到字符串,也是存放在一个描述符号中,但是会将指针指向最后一个字符上;接收进程发现字符上有带外数据标记,会发送信号SIGURG(紧急数据),即带外数据的优先级体现在信号的优先。
使用带外数据的实际例子telnet、rlogin、ftp命令,前两个命令会将中止字符作为紧急数据发送到远端,这会使得远端冲洗所有未处理的输入,并且丢弃所有为发送的终端输入,会快速中断一个向屏幕发送大量数据的运行进程;ftp命令使用带外数据来中断一个文件的传输。
在循环发送数据时,带外数据标记可能会被覆盖,导致形成一长串字符,只有最后一个被标记带外数据,其他的被覆盖。
案例:
客户程序send函数设置为MSG_OOB:
服务器接收数据recv两次:
a.不设置为MSG_OOB标志,服务器接收的数据没有最后一个字符;
b.设置为MSG_OOB标志,只会接收到一个字符,也就是带外数据。
oob_server.c recv MSG_OOBoob_client.c send MSG_OOB
- 1
- 2
- 3
- 4
对于这个实例,客户端程序发送带外数据,服务器端有两种方式可以接受数据,信号和select。
客户端程序如下:
/** * oob_client.c * */main(){ int fd; int r; struct sockaddr_in dr; fd=socket(AF_INET,SOCK_STREAM,0); if(fd==-1) printf("socket err:%m\n"),exit(-1); dr.sin_family=AF_INET; dr.sin_port=htons(9999); dr.sin_addr.s_addr=inet_addr("192.168.245.149"); r=connect(fd,(struct sockaddr*)&dr,sizeof(dr)); if(r==-1) printf("connect err:%m\n"),exit(-1); r=send(fd,"hello tty",9,MSG_OOB); //发送带外数据,只有最后一个字节被标识为带外数据,其他的为普通数据,并且带外数据会优先于普通数据到达 if(r==-1) printf("send err:%m\n"),exit(-1); close(fd);}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
1. 使用SIGURG信号处理带外数据
/** * oob_server_signal.c **/void handle(int s){ int r; char data[100]; r=recv(cfd,data,100,MSG_OOB); if(r>0){ data[r]=0; printf("接收带外数据:%s\n",data); }}main(){ /*此处为server建立socket,并bind地址*/ fcntl(cfd,F_SETOWN,getpid()); //将进程创建为套接口的所有者,使得带外数据到达时,内核向进程发送一个SIGURG信号 signal(SIGURG,handle); while(1) { r=recv(cfd,buf,1024,0); if(r>0) { buf[r]=0; printf("普通数据:%s\n",buf); } else break; } ...}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
运行结果:
[ty@tiany I_O]$ ./oob_server_signal 接收带外数据:y普通数据:hello tt
- 1
- 2
- 3
由输出可以发现字符串最后一个字符‘y’先被接收到,正是体现的带外数据的紧急特性,也就是TCP的紧急模式。
2. 使用select异常接收带外数据
int main(int argc, char **argv) { /*此处为server建立socket,并bind地址,省略*/ char buf[1024]; //buf缓冲区接收数据(普通数据和带外数据) fd_set read_fds; //接收普通数据,放入读事件集合中 fd_set exceptions_fds; //接收带外数据,发生异常,放入异常事件集合中 FD_ZERO(&read_fds); FD_ZERO(&exceptions_fds); while(1) { FD_SET(connfd,&read_fds); FD_SET(connfd,&exceptions_fds); ret = select(connfd+1,&read_fds,NULL,&exceptions_fds,NULL); if(FD_ISSET(connfd,&read_fds)){ memset(buf,0x00,sizeof(buf)); ret = recv(connfd,buf,sizeof(buf)-1,0); } if(FD_ISSET(connfd,&exceptions_fds)) { memset(buf,0x00,sizeof(buf)); ret =recv(connfd,buf,sizeof(buf)-1,MSG_OOB); } } ... }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
对于select函数的使用参看我上一边博文。
完整代码获取链接:https://github.com/ty92/OOB
- TCP带外数据OOB
- TCP带外数据OOB
- 关于TCP带外数据(OOB,Out Of Bound)
- 小议TCP带外数据(OOB--out of band)
- OOB(out of band):带外数据
- 带外数据OOB与紧急模式URG
- 带外数据OOB与紧急模式URG
- 带外数据OOB与紧急模式URG
- 带外数据OOB与紧急模式URG
- [转载]带外数据OOB与紧急模式URG
- 带外数据OOB与紧急模式URG
- 带外数据OOB与紧急模式URG
- tcp 带外数据
- 关于带外数据OOB与紧急模式URG的几篇文章
- 关于TCP带外数据
- TCP带外数据测试
- tcp带外数据连接
- tcp发送带外数据
- 201312-5 I'm stuck!
- linux下的关机命令和重启命令
- DeviceIoControl 直接从磁盘扇区读文件
- 我的学习记录31
- XML多个根节点提示“文档中根元素后面的标记必须格式正确”解决
- TCP带外数据OOB
- Ajax(原生js实现、jQuery实现、跨域)
- 《Python核心编程》 第3版 中文版pdf
- 八.ARM裸机学习之S5PV210的时钟系统1(原理概念及框图分析)
- Tomcat溢出、Java内存溢出
- linux mint下安装apache,php
- 1174 明明的随机数
- 小白快速部署Spark-2.2.0集群(附通俗解释)
- TCP/IP实验获取主机网卡信息