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