关于TCP带外数据

一、

读UNP,看到24章的带外数据。书上还给出了一个小例子 ------ 一个服务端接收普通数据和带外数据,另外有个客户端发送普通数据和带外数据。接收端的普通数据和带外数据是分开接收的。普通数据就用普通的recv,而带外数据是在SIGURG信号处理函数里面用recv(... MSG_OOB)接收的。我冒出个想法,在SIGURG信号处理函数里面,如果我在recv( MSG_OOB)之前用普通的recv接收普通的数据,能否接收到什么。代码如下:

void
sig_urg(int signo)
{
    printf("SIGURG received\n");

    // 我增加的
    if ((n = recv(connfd, buf, size(buf)-1, MSG_DONTWAIT)) == -1) {
    if (errno == EAGAIN) 
        perror("err, EAGAIN");
    }

    if ((n = recv(connfd, buf, sizeof(buf)-1, MSG_OOB) == -1) {
        perror("recv MSG_OOB error");
        return;
    }
    buf[n] = '\0';
    printf("read %d bytes: %s\n", n, buf);
}

中间那几行是我增加的。我是这么想的:这个信号处理函数被调用时,肯定是套接字进程收到了SIGURG信号了,即套接字中有紧急数据。但是此时并没有普通数据(这个通过发送端控制)。所以我增加的那一段代码,应该走到perror("err, EAGAIN")。然后接着往下,recv(... MSG_OOB)应该能接收到带外数据(发送端控制带外数据发送过来)。可是运行结果出我意料:recv(...MSG_OOB)出现argument invalid错误,也就是说没有收到带外数据。把我增加的那部分代码去掉,就能接收带外数据。

 recv(connfd, buf, size(buf)-1, MSG_DONTWAIT))把带外数据弄没了,为什么?这个是接收普通数据的啊,为什么会影响到带外数据呢?要看看内核是如何实现的。

还有一点要注意:如果带外数据发了2个字节过来,接收端怎么处理?接收端触发SIGURT信号,进入sig_urg函数,recv( MSG_OOB)只能接收到一个字节----带外数据的最后一个字节。剩下的字节会由普通的recv(...)读取到。

二、sockatmark函数

既然有了sig_urg, recv( MSG_OOB)了,为什么还要这个函数呢?查一下man page,它几句话就表达清楚了。 sockatmark()  returns  a value indicating whether or not the socket referred to by the file descriptor fd is at the out-of-band mark...。

现在来看看到底"at the out-of-band mark"指什么语义,它是指接收到一个TCP包(头部设置了URG),还是指真正的带外数据到达。注意这两者是有区别的。书上有句话:”在接收进程已被告知对端发送了一个带外数据(通过SIGURG或select)的前提下,如果接收进程试图读入该字节,但是该字节尚未达到,...“。怎么会有这种情况发生呢?当发送端调用recv(fd, "aaaaa", 5, MSG_OOB),tcp封包,但是由于自己缓冲满了,或者对端MSS窗口很小而容不下5个字节时,就会产生两个TCP包,第一个包设置了URG但真正带外数据并不在内,后面第二个包才真正包含那个带外数据。这时候接收端就会出现书上那句话的情况。

而sockatmark就是用来判断真正的带外数据到达。man page中的例子很好的说明了它的用途:

  //The following code can be used after receipt of a SIGURG signal to read (and discard) all  data  up  to  the
       mark, and then read the byte of data at the mark:

           char buf[BUF_LEN];
           char oobdata;
           int atmark, s;

           for (;;) {
               atmark = sockatmark(fd);
               if (atmark == -1) {
                   perror("sockatmark");
                   break;
               }

               if (atmark)
                   break;

               s = read(fd, buf, BUF_LEN) <= 0);
               if (s == -1)
                   perror("read");
               if (s <= 0)
                   break;
           }

           if (atmark == 1) {
               if (recv(fd, &oobdata, 1, MSG_OOB) == -1) {
                   perror("recv");
                   ...
               }
           }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值