hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

[apue] 怎样处置惩罚 tcp 紧要数据(OOB)?

2019-11-18杂谈搜奇网43°c
A+ A-

在上大学的时刻,我们能够就听说了OOB(Out Of Band 带外数据,又称紧要数据)这个观点。

当时先生给的诠释就是在当前处置惩罚的数据流以外的数据,用于紧要的状况。然后就没有然后了……

毕业这么多年了,追念一下,还真是没有打仗过OOB的场景,更没有实地发送、吸收过OOB。

那末究竟该如何处置惩罚OOB呢?OOB在所谓的紧要状况下是不是有效呢?下面一一道来。

 

起首发生OOB是异常简朴的,只须要在平常send的末了一个参数,到场MSG_OOB标志位:

ret = send (sockfd, ptr, n, MSG_OOB);

假如斟酌一个完全的测试场景,须要有惯常数据,中心夹带OOB数据,如许才比较好的测试吸收端是不是能准确的辨别他们,

所以客户端能够写成如许:

 1     strcpy(buf, "abcdefghijklmn"); 
 2     char const* ptr = buf; 
 3     if ((ret = send (sockfd, ptr, 2, 0)) < 0)
 4         err_sys ("send normal head failed"); 
 5     else 
 6         printf ("send normal head %d\n", ret); 
 7 
 8     ptr += 2; 
 9     n = 1; 
10     if ((ret = send (sockfd, ptr, n, MSG_OOB)) < 0)
11         err_sys ("send oob failed"); 
12     else 
13         printf ("send oob %d\n", ret); 
14 
15     ptr += n; 
16     if ((ret = send (sockfd, ptr, 2, 0)) < 0)
17         err_sys ("send normal tail failed"); 
18     else 
19         printf ("send normal tail %d\n", ret); 

算法比较简朴,先发送2字节惯常数据,接着1字节OOB,末了2字节惯常数据末端。

须要注重的是,现在只要TCP支撑OOB,UDP没所谓递次,更没所谓带内带外之分,所以也没有OOB;

别的TCP现在大多数完成只支撑1字节OOB,大于1字节的OOB,只要末了一字节会被当为OOB处置惩罚,之前的作为一般数据。

 

然后我们来讲一下吸收OOB的三种要领:

1. 运用SIGURG信号特地处置惩罚OOB

这类要领是将OOB与惯常数据离开处置惩罚,具体步骤以下:

a) 历程肇端时,竖立SIGURG信号处置惩罚器

1     struct sigaction sa; 
2     sa.sa_handler = on_urg; 
3     sa.sa_flags |= SA_RESTART; 
4     sigemptyset (&sa.sa_mask); 
5     sigaction (SIGURG, &sa, NULL); 

b) 竖立新衔接时,设置衔接句柄的信号处置惩罚历程(为当前历程)

1 fcntl (clfd, F_SETOWN, getpid ()); 

c) 在信号处置惩罚器中运用MSG_OOB吸收带外数据

 1 int g_fd = 0; 
 2 void on_urg (int signo)
 3 {
 4     int ret = 0; 
 5     char buf[BUFLEN] = { 0 }; 
 6     ret = recv (g_fd, buf, sizeof (buf), MSG_OOB); 
 7     if (ret > 0)
 8         buf[ret] = 0; 
 9     else 
10         strcpy (buf, "n/a"); 
11 
12     printf ("got urgent data on signal %d, len %d, %s\n", signo, ret, buf); 
13 
14 }

d) 惯常数据,能够在主处置惩罚流程中运用不带MSG_OOB的recv,像之前那样处置惩罚

1         ret = recv (clfd, buf, sizeof(buf), 0); 
2         if (ret > 0)
3             buf[ret] = 0; 
4         else 
5             strcpy (buf, "n/a"); 
6 
7         printf ("recv %d: %s\n", ret, buf); 

由于惯常数据的吸收,会被OOB打断,因而这里能够须要一个轮回,不停吸收惯常数据。

下面是要领1的吸收输出:

hostname length: 64
get hostname: localhost.localdomain
setup SIGURG for oob data
setown to 31793
got urgent data on signal 23, len 1, c
recv 2: ab
has oob!
recv -1: n/a
recv 2: de
write back 70
recv 2: ab
recv 2: ab
got urgent data on signal 23, len 1, c
has oob!
recv -1: n/a
recv 2: de
write back 70
recv 2: ab
no oob!
got urgent data on signal 23, len 1, c
recv 2: de
write back 70
recv 2: ab
recv 2: ab
got urgent data on signal 23, len 1, c
has oob!
recv -1: n/a
recv 2: de
write back 70
^C

 能够看到信号处置惩罚器中吸收到的老是OOB数据'c',而一般recv只能读到非OOB数据'a''b''d''e'。而且一般数据的吸收,会被OOB数据打断成两块,没法一次性读取。

 

2.运用SO_OOBINLINE标志位将OOB作为惯常数据处置惩罚

这类要领是将OOB数据看成惯常数据吸收,在吸收前经由过程推断哪些是一般数据哪些是OOB数据,具体步骤以下:

a) 新衔接竖立时,设置套接字选项SO_OOBINLINE

1 setsockopt (fd, SOL_SOCKET, SO_OOBINLINE, &oil, sizeof (oil));

b) 在吸收数据前,先推断下一个字节是不是为OOB,假如是,则吸收1字节OOB数据(注重不运用MSG_OOB标志)

 1         if (sockatmark (clfd))
 2         {
 3             printf ("has oob!\n"); 
 4             ret = recv (clfd, buf, sizeof(buf), 0); 
 5             if (ret > 0)
 6                 buf[ret] = 0; 
 7             else 
 8                 strcpy (buf, "n/a"); 
 9 
10             printf ("recv %d: %s\n", ret, buf); 
11         }
12         else 
13             printf ("no oob!\n"); 

这里sockatmark当下个字节为OOB时返回1,不然返回0。

c) 假如不是,按惯常数据吸收

1         ret = recv (clfd, buf, sizeof(buf), 0); 
2         if (ret > 0)
3             buf[ret] = 0; 
4         else 
5             strcpy (buf, "n/a"); 
6 
7         printf ("recv %d: %s\n", ret, buf); 

同理,由于惯常数据会被OOB打断,上述代码老是能够准确的星散OOB与一般数据。

下面是要领2的吸收输出:

hostname length: 64
get hostname: localhost.localdomain
setown to 31883
recv 2: ab
no oob!
recv 3: cde
write back 70
recv 2: ab
has oob!
recv 1: c
recv 2: de
write back 70
recv 2: ab
has oob!
recv 1: c
recv 2: de
write back 70
recv 2: ab
no oob!
recv 3: cde
write back 70
recv 2: ab
has oob!
recv 1: c
recv 2: de
write back 70
^C

 能够看出,有时刻OOB数据不能被一般的辨认,会被看成一般数据处置惩罚掉。而且这类体式格局也不能表现OOB紧要的意义,没有赋予它优先的处置惩罚权。

 

3.运用 select/epoll 多路事宜星散

这类要领是应用select或epoll,将OOB数据作为exception事宜与一般数据的read事宜相星散,这里以select为例:

a) 竖立 select 事宜处置惩罚轮回

1     for (;;) { 
2         // must set it in every loop.
3         memcpy (&rdds, &cltds, sizeof (cltds)); 
4         memcpy (&exds, &cltds, sizeof (cltds)); 
5         FD_SET(sockfd, &rdds); 
6         ret = select (FD_SIZE+1, &rdds, NULL, &exds, NULL); 
7         ……
8     }

b) 竖立衔接时,将衔接fd到场待监听fd_set

 1             if (FD_ISSET(clfd, &rdds))
 2             {
 3                if (clfd == sockfd)
 4                {
 5                    // the acceptor
 6                     printf ("poll accept in\n"); 
 7                     clfd = accept (sockfd, NULL, NULL); 
 8                     if (clfd < 0) { 
 9                         printf ("accept error: %d, %s\n", errno, strerror (errno)); 
10                         exit (1); 
11                     }
12 
13                     print_sockopt (clfd, "new accepted client"); 
14                     // remember it
15                     FD_SET(clfd, &cltds); 
16                     printf ("add %d to client set\n", clfd); 
17                } 
18                else 
19                {
20                     ……
21                }
22             }            

c) 衔接上有数据抵达时,假如是read事宜,运用recv吸收数据

 1             if (FD_ISSET(clfd, &rdds))
 2             {
 3                if (clfd == sockfd)
 4                {
 5                    ……
 6                } 
 7                else 
 8                {
 9                    // the normal client
10                    printf ("poll read in\n"); 
11                    ret = recv (clfd, buf, sizeof(buf), 0); 
12                    if (ret > 0)
13                        buf[ret] = 0; 
14                    else 
15                        sprintf (buf, "errno %d", errno); 
16 
17                    printf ("recv %d from %d: %s\n", ret, clfd, buf); 
18                    if (ret <= 0) {
19                        FD_CLR(clfd, &cltds); 
20                        printf ("remove %d from client set\n", clfd); 
21                    }
22                }
23             }

d) 假如是exception事宜,运用recv(..,MSG_OOB)吸收带外数据

 1             if (FD_ISSET(clfd, &exds))
 2             {
 3                 // the oob from normal client
 4                 printf ("poll exception in\n"); 
 5                 if (sockatmark (clfd))
 6                 {
 7                     printf ("has oob!\n"); 
 8                     ret = recv (clfd, buf, 1, MSG_OOB); 
 9                     if (ret > 0)
10                         buf[ret] = 0; 
11                     else 
12                        sprintf (buf, "errno %d", errno); 
13 
14                     printf ("recv %d from %d on urgent: %s\n", ret, clfd, buf); 
15                     if (ret > 0) {
16                         // let clfd cleared in sig_cld
17                        do_uptime (clfd); 
18                     }
19                     else 
20                     {
21                         FD_CLR(clfd, &cltds); 
22                         printf ("remove %d from client set\n", clfd); 
23                     }
24                 }
25                 else 
26                     printf ("no oob!\n"); 
27             }

此时,仍可运用sockatmark来推断是不是为OOB数据,别的,假如在衔接竖立时设定了OOB_INLINE标志位,则此处应运用不带MSG_OOB的recv吸收数据,

由于OOB数据已被看成惯常数据来处置惩罚了,此处与要领2是一致的。

下面是要领3的输出:

setup handler for SIGCHLD ok
hostname length: 64
get hostname: localhost.localdomain
got event 1
poll accept in
add 4 to client set
got event 2
poll read in
recv 2 from 4: ab
poll exception in
has oob!
recv 1 from 4 on urgent: c
start worker process 4511
goto serve next client..
got event 1
poll read in
recv 2 from 4: de
got event 1
poll accept in
add 5 to client set
got event 2
poll read in
recv 2 from 5: ab
poll exception in
has oob!
recv 1 from 5 on urgent: c
start worker process 4513
goto serve next client..
got event 1
poll read in
recv 2 from 5: de
got event 1
poll accept in
add 6 to client set
got event 2
poll read in
recv 2 from 6: ab
poll exception in
has oob!
recv 1 from 6 on urgent: c
start worker process 4516
goto serve next client..
got event 1
poll read in
recv 2 from 6: de
SIGCHLD received
wait child 4511 return 0
find clfd 4 for that pid
remove 4 from client set
interrupted by signal, some child process done ?
SIGCHLD received
wait child 4513 return 0
find clfd 5 for that pid
remove 5 from client set
interrupted by signal, some child process done ?
SIGCHLD received
wait child 4516 return 0
find clfd 6 for that pid
remove 6 from client set
interrupted by signal, some child process done ?
^C

须要注重的是,在某些场景下,OOB会被辨认为惯常数据,此时exception事宜在处置惩罚时将得不到OOB数据,不过这有肯定的随机性,不是每次都能复现。

 

 

末了,总结一下OOB这个功用。

这么多年来没有碰到OOB的处置惩罚,能够自身就说清楚明了人人对它的立场——就是挺鸡肋的一功用,

而且纵然真的须要紧要处置惩罚了,1字节的限定也致使不能通报什么更多的信息,且自身OOB的处置惩罚又有些庞杂和局限性,

比方运用信号处置惩罚器,假如有多个衔接,我怎样晓得是哪一个衔接上的OOB?

假如运用SO_OOBINLINE,OOB被看成一般数据,这里面假如有个构造体被生生插进去一个OOB字节,

而且还没有准确辨认出来,这里面的对齐题目可要了老命了。

 

 

所以末了的结论是:OOB是过期的,请不要运用它

 

测试顺序1

测试顺序2

测试顺序3

 

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
[apue] 怎样处置惩罚 tcp 紧要数据(OOB)?

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282271.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>