许多传输层有带外数据的概念,它有时也称为经加速数据。其想法是一个连接的某端发生了重要的事情,而且该端希望迅速告知其对端。
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);