TCP带外数据(OOB)的发送与接收


带外数据比普通数据具有更高的优先级,TCP没有真正的带外数据,而是提供了一个我们要讨论的紧急模式,TCP将数据放置在套机口发送缓冲区的下一个可用位置,并设置这个连接的TCP紧急指针(urgent pointer)为下一个可用位置,TCP紧急指针有一个比用MSG_OOB标志写入的数据多一个字节的序列号。由于接收端的带外缓冲只有1Byte所以发送端发送的多字节带外数据只有最后1Byte被当做带外数据,若接收端TCP连接设置了SO_OOBINLINE选项则带外数据和普通数据一样存放于TCP接收缓冲区中。带外数据的发送与接收可以调用含有MSG_OOB标志的send和recv。sockatmark(int sockfd)可以判断sockfd下一个数据是否含有带外数据,若有就可以调用含有MSG_OOB标志的recv接收带外数据,接收带外数据的方式是带有MSG_OOB的recv接收

检测带外数据到来的方法:

1 sockatmark(int sockfd)

2 由于带外数据对于select返回是异常事件所以可以由select返回判断带外数据到来

3 通过SIG_URG信号处理函数

 

发送带外数据的客户端程序

 1 /*
 2  * 带外数据发送端
 3  * oob_client.c
 4  * Created on: Oct 30, 2016
 5  * Author: zhangming
 6  */
 7 #include <stdio.h>
 8 #include <stdlib.h>
 9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 
15 #define SEND_NORMAL_DATA "123"
16 #define SEND_OOB_DATA "abc"  //其中只有最后的字符'c'会被当做带外数据
17 
18 int main(int argc, char **argv) {
19     int fd=socket(AF_INET,SOCK_STREAM,0);
20     if(fd==-1) printf("1:%m\n"),exit(-1);
21 
22     struct sockaddr_in dr;
23     dr.sin_family = AF_INET;
24     dr.sin_port = htons(10000);
25     dr.sin_addr.s_addr = inet_addr("192.168.209.128");
26 
27     int result = connect(fd,(struct sockaddr*)&dr,sizeof(dr));
28     if(result==-1) printf("2:%m\n"),exit(-1);
29 
30     fd_set fds;
31     FD_ZERO(&fds);
32     FD_SET(fd,&fds);
33     select(fd+1,0,&fds,0,0);
34     send(fd,SEND_NORMAL_DATA,strlen(SEND_NORMAL_DATA),0); //发送正常数据
35     //注意: 带外数据,接收端的带外缓存只有1Byte,所以只有字符'c'是真正的带外数据,同理带MSG_OOB标志的recv能接收带外数据
36     send(fd,SEND_OOB_DATA,strlen(SEND_OOB_DATA),MSG_OOB); //使用带外数据标志flag=MSG_OOB
37 
38     close(fd);
39 }

 

接收带外数据的服务端程序(采用SIGURG信号检测带外数据的到来)

 1 /*
 2  * 带外数据接收端
 3  * oob_server.c
 4  * Created on: Oct 30, 2016
 5  * Author: zhangming
 6  */
 7 #include <stdio.h>
 8 #include <stdlib.h>
 9 #include <unistd.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
13 #include <signal.h>
14 #include <fcntl.h>
15 
16 int fd,cfd;
17 
18 void handle(int s){
19     char data[100];
20     if(s==SIGURG){
21         int r = recv(cfd,data,sizeof(data),MSG_OOB);
22         data[r] = 0;
23         printf("接收%d字节的带外数据(oob data): %s\n",r,data);
24     }
25 }
26 
27 int main(int argc, char **argv) {
28     fd=socket(AF_INET,SOCK_STREAM,0);
29     if(fd==-1) printf("1:%m\n"),exit(-1);
30 
31     struct sockaddr_in dr;
32     dr.sin_family = AF_INET;
33     dr.sin_port = htons(10000);
34     dr.sin_addr.s_addr = inet_addr("192.168.209.128");
35 
36     int result = bind(fd,(struct sockaddr*)&dr,sizeof(dr));
37     if(result==-1) printf("2:%m\n"),exit(-1);
38 
39     result = listen(fd,10);
40     if(result==-1) printf("3:%m\n"),exit(-1);
41 
42     signal(SIGURG,handle); //添加SIGURG信号
43     cfd = accept(fd,0,0); //建立客户端连接
44     if(cfd==-1) printf("4:%m\n"),exit(-1);
45     fcntl(cfd,F_SETOWN,getpid()); //SIGURG的前提条件是进程必须持有文件描述符cfd
46 
47     char buf[100];
48     while(1){
49         int r = recv(cfd,buf,sizeof(buf),0);
50         if(r>0){
51             buf[r]=0;
52             printf("接收%d字节的正常数据(normal data):%s\n",r,buf);
53             sleep(1);
54         }else{
55             break;
56         }
57     }
58 
59     close(cfd);
60     close(fd);
61 }

 

运行结果截图:


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM