《UNP》第24章-带外数据

许多传输层有带外数据的概念,它有时也称为经加速数据。其想法是一个连接的某端发生了重要的事情,而且该端希望迅速告知其对端。
UDP没有实现带外数据
TCP的带外数据大小为1个字节

send(fd,"abc",3,MSG_OOB);
//这样的话最后那个字节(也就是c)被认为是带外字节

使用SIGURG的简单例子

重点

Signal(SIGURG,sig_urg);
Fcntl(connfd,F_SETOWN,getpid());//设属主,这样才能接受SIGURG信号

//tcpsend01.c
#include "unp.h"
int
main(int argc, char **argv)
{
        int sockfd;
        if(argc!=3)
                err_quit("usage: tcpsend01  ");
        sockfd=Tcp_connect(argv[1],argv[2]);

        Write(sockfd,"123",3);
        printf("wrote 3 bytes of normal data\n");
        sleep(1);

        Send(sockfd,"4",1,MSG_OOB);
        printf("wrote 1 byte of OOB data\n");
        sleep(1);

        Write(sockfd,"56",2);
        printf("wrote 2 bytes of normal data\n");
        sleep(1);

        Send(sockfd,"7",1,MSG_OOB);
        printf("wrote 1 byte of OOB date\n");
        sleep(1);

        Write(sockfd,"89",2);
        printf("wrote 2 bytes of normal data\n");
        sleep(1);

        exit(0);
}
//tcprecv01.c
int listenfd,connfd;
void sig_urg(int);

int main(int argc, char **argv)
{
        int n;
        char buff[100];

        if(argc==2)
                listenfd=Tcp_listen(NULL,argv[1],NULL);
        else if(argc==3)
                listenfd=Tcp_listen(argv[1],argv[2],NULL);
        else
                err_quit("usage:tcprecv01 [] ");
        connfd=Accept(listenfd,NULL,NULL);
        Signal(SIGURG,sig_urg);
        Fcntl(connfd,F_SETOWN,getpid());//设属主,这样才能接受SIGURG信号
        for(;;){
                if((n=Read(connfd,buff,sizeof(buff)-1))==0){
                        printf("received EOF\n");
                        exit(0);
                }
                buff[n]=0;
                printf("read %d bytes: %s\n",n,buff);
        }
}

void
sig_urg(int signo)
{
        int n;
        char buff[100];

        printf("SIGURG recevied\n");
        n=Recv(connfd,buff,sizeof(buff)-1,MSG_OOB);
        buff[n]=0;
        printf("read %d OOB byte: %s\n",n,buff);
}

sockatmark函数

#include 
int sockatmark(int sockfd);
//若处于带外标记1,若不处于带外标记则0,出错为-1

如果带外数据在线接收,那么如果下一个待读入的字节是使用MSG_OOB标志发送的,sockatmark就返回真。而如果SO_OOBINLINE套接字没有开启,那么,若下一个待读入的字节是跟在带外数据后发送的第一个字节,sockatmark就返回真。

……
Setsockopt(listenfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
……
if (Sockatmark(connfd))
                        printf("at OOB mark\n");

使用select的简单例子

                FD_SET(connfd, &rset);
                if (justreadoob == 0)
                        FD_SET(connfd, &xset);

                Select(connfd + 1, &rset, NULL, &xset, NULL);

                if (FD_ISSET(connfd, &xset)) {
                        n = Recv(connfd, buff, sizeof(buff)-1, MSG_OOB);
                        buff[n] = 0;            /* null terminate */
                        printf("read %d OOB byte: %s\n", n, buff);
                        justreadoob = 1;
                        FD_CLR(connfd, &xset);
                }

                if (FD_ISSET(connfd, &rset)) {
                        if ( (n = Read(connfd, buff, sizeof(buff)-1)) == 0) {
                                printf("received EOF\n");
                                exit(0);
                        }
                        buff[n] = 0;    /* null terminate */
                        printf("read %d bytes: %s\n", n, buff);
                        justreadoob = 0;
                }
        }

select一直指示一个异常条件,直到进程的读入越过带外数据
所以得手动FD_CLR(connfd,&xset);

你可能感兴趣的:(《UNP》第24章-带外数据)