TCP带外数据OOB

原文地址: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_OOB
oob_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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值