客户端代码
#include <iostream>
#include <cstring>
#include <cassert>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
using namespace std;
/*
* 参数1:ip地址
* 参数2:端口号
* */
int main(int argc, char* argv[])
{
if (argc <= 2) return -1;
/* 设置服务端ip和端口号 */
string ip(argv[1]);
int port = atoi(argv[2]);
/* 创建socket地址 */
sockaddr_in saddr;
bzero(&saddr, sizeof saddr);
saddr.sin_family = AF_INET;
inet_pton(AF_INET, ip.c_str(), &saddr.sin_addr);
saddr.sin_port = htons(port);
/* 创建socket文件描述符 */
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
assert(sockfd >= 0);
/* 客户端发起连接 */
int ret = connect(sockfd, (sockaddr*)&saddr, sizeof saddr);
assert(ret != -1);
/* 数据读写 */
string oob_data("abc");
string nor_data("123");
/*发送正常数据,带外数据,正常数据*/
send(sockfd, nor_data.c_str(), nor_data.size(), 0);
send(sockfd, oob_data.c_str(), oob_data.size(), MSG_OOB);
send(sockfd, nor_data.c_str(), nor_data.size(), 0);
/* 关闭连接 */
close(sockfd);
return 0;
}
服务端代码
#include <iostream>
#include <cstring>
#include <cassert>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
using namespace std;
/*
* 参数1:ip地址
* 参数2:端口号
* */
const int BUF_SIZE = 1024;
int main(int argc, char* argv[])
{
if (argc <= 2) return -1;
/* 服务端ip和端口号 */
string ip(argv[1]);
int port = atoi(argv[2]);
/* 创建socket地址 */
sockaddr_in addr;
bzero(&addr, sizeof addr);
addr.sin_family = AF_INET;
inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
addr.sin_port = htons(port);
/* 创建socket文件描述符 */
int lisfd = socket(PF_INET, SOCK_STREAM, 0);
assert(lisfd >= 0);
/* 绑定socket文件描述符和socket地址 */
int ret = bind(lisfd, (sockaddr*)&addr, sizeof addr);
assert(ret != -1);
/* 设置监听 */
ret = listen(lisfd, 20);
assert(ret != -1);
/* 接收连接 */
sockaddr_in cliaddr;
socklen_t len = sizeof cliaddr;
int connfd = accept(lisfd, (sockaddr*)&cliaddr, &len);
assert(connfd >= 0);
/* 接收数据并显示 */
char buffer[BUF_SIZE];
memset(buffer, '\0', BUF_SIZE);
ret = recv(connfd, buffer, BUF_SIZE - 1, 0);
printf("got %d bytes og normal data '%s'\n", ret, buffer);
memset(buffer, '\0', BUF_SIZE);
ret = recv(connfd, buffer, BUF_SIZE - 1, 0);
printf("got %d bytes og oob data '%s'\n", ret, buffer);
memset(buffer, '\0', BUF_SIZE);
ret = recv(connfd, buffer, BUF_SIZE - 1, 0);
printf("got %d bytes og normal data '%s'\n", ret, buffer);
/* 关闭所有打开的文件描述符 */
close(connfd);
close(lisfd);
return 0;
}
./Client带外数据 127.0.0.1 54231
./Server带外数据 127.0.0.1 54231
下面是上面设置MSG_OOB选项后服务端接收的数据
got 3 bytes og normal data '123ab'
got 2 bytes og oob data 'c'
got 3 bytes og normal data '123'
假如不设置MSG_OOB选项服务器接收是这样的
got 9 bytes og normal data '123abc123'
got 0 bytes og oob data ''
got 0 bytes og normal data ''
可以看到服务器对正常数据的接收被带外数据截断,并且只有ab被当做带外数据。
通过tcpdump观察原因
sudo tcpdump -ntx -i lo port 54213
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
/**** 第一次握手 ****/
IP 127.0.0.1.50670 > 127.0.0.1.54231: Flags [S], seq 245814392, win 65495, options [mss 65495,sackOK,TS val 1700334657 ecr 0,nop,wscale 7], length 0
0x0000: 4500 003c 77f7 4000 4006 c4c2 7f00 0001
0x0010: 7f00 0001 c5ee d3d7 0ea6 d478 0000 0000
0x0020: a002 ffd7 fe30 0000 0204 ffd7 0402 080a
0x0030: 6559 0c41 0000 0000 0103 0307
/**** 第二次握手 ****/
IP 127.0.0.1.54231 > 127.0.0.1.50670: Flags [S.], seq 2155847100, ack 245814393, win 65483, options [mss 65495,sackOK,TS val 1700334657 ecr 1700334657,nop,wscale 7], length 0
0x0000: 4500 003c 0000 4000 4006 3cba 7f00 0001
0x0010: 7f00 0001 d3d7 c5ee 807f 9dbc 0ea6 d479
0x0020: a012 ffcb fe30 0000 0204 ffd7 0402 080a
0x0030: 6559 0c41 6559 0c41 0103 0307
/**** 第三次握手 ****/
IP 127.0.0.1.50670 > 127.0.0.1.54231: Flags [.], ack 1, win 512, options [nop,nop,TS val 1700334657 ecr 1700334657], length 0
0x0000: 4500 0034 77f8 4000 4006 c4c9 7f00 0001
0x0010: 7f00 0001 c5ee d3d7 0ea6 d479 807f 9dbd
0x0020: 8010 0200 fe28 0000 0101 080a 6559 0c41
0x0030: 6559 0c41
/**** 客户端发送正常数据"123" ****/
IP 127.0.0.1.50670 > 127.0.0.1.54231: Flags [P.], seq 1:4, ack 1, win 512, options [nop,nop,TS val 1700334658 ecr 1700334657], length 3
0x0000: 4500 0037 77f9 4000 4006 c4c5 7f00 0001
0x0010: 7f00 0001 c5ee d3d7 0ea6 d479 807f 9dbd
0x0020: 8018 0200 fe2b 0000 0101 080a 6559 0c42
0x0030: 6559 0c41 3132 33
/**** 服务端收到并确认 ****/
IP 127.0.0.1.54231 > 127.0.0.1.50670: Flags [.], ack 4, win 512, options [nop,nop,TS val 1700334658 ecr 1700334658], length 0
0x0000: 4500 0034 42fe 4000 4006 f9c3 7f00 0001
0x0010: 7f00 0001 d3d7 c5ee 807f 9dbd 0ea6 d47c
0x0020: 8010 0200 fe28 0000 0101 080a 6559 0c42
0x0030: 6559 0c42
/**** 客户端发送紧急数据"abc", Flags[U]标识 *****/
IP 127.0.0.1.50670 > 127.0.0.1.54231: Flags [P.U], seq 4:7, ack 1, win 512, urg 3, options [nop,nop,TS val 1700334659 ecr 1700334658], length 3
0x0000: 4500 0037 77fa 4000 4006 c4c4 7f00 0001
0x0010: 7f00 0001 c5ee d3d7 0ea6 d47c 807f 9dbd
0x0020: 8038 0200 fe2b 0003 0101 080a 6559 0c43
0x0030: 6559 0c42 6162 63
/**** 客户端发送正常数据"123" ****/
IP 127.0.0.1.54231 > 127.0.0.1.50670: Flags [.], ack 7, win 512, options [nop,nop,TS val 1700334659 ecr 1700334659], length 0
0x0000: 4500 0034 42ff 4000 4006 f9c2 7f00 0001
0x0010: 7f00 0001 d3d7 c5ee 807f 9dbd 0ea6 d47f
0x0020: 8010 0200 fe28 0000 0101 080a 6559 0c43
0x0030: 6559 0c43
/**** 服务端收到并确认 ****/
IP 127.0.0.1.50670 > 127.0.0.1.54231: Flags [P.], seq 7:10, ack 1, win 512, options [nop,nop,TS val 1700334659 ecr 1700334659], length 3
0x0000: 4500 0037 77fb 4000 4006 c4c3 7f00 0001
0x0010: 7f00 0001 c5ee d3d7 0ea6 d47f 807f 9dbd
0x0020: 8018 0200 fe2b 0000 0101 080a 6559 0c43
0x0030: 6559 0c43 3132 33
/**** 第一次挥手 ****/
IP 127.0.0.1.54231 > 127.0.0.1.50670: Flags [.], ack 10, win 512, options [nop,nop,TS val 1700334659 ecr 1700334659], length 0
0x0000: 4500 0034 4300 4000 4006 f9c1 7f00 0001
0x0010: 7f00 0001 d3d7 c5ee 807f 9dbd 0ea6 d482
0x0020: 8010 0200 fe28 0000 0101 080a 6559 0c43
0x0030: 6559 0c43
/**** 第二次挥手 ****/
IP 127.0.0.1.54231 > 127.0.0.1.50670: Flags [F.], seq 1, ack 10, win 512, options [nop,nop,TS val 1700334659 ecr 1700334659], length 0
0x0000: 4500 0034 4301 4000 4006 f9c0 7f00 0001
0x0010: 7f00 0001 d3d7 c5ee 807f 9dbd 0ea6 d482
0x0020: 8011 0200 fe28 0000 0101 080a 6559 0c43
0x0030: 6559 0c43
/**** 第三次挥手 ****/
IP 127.0.0.1.50670 > 127.0.0.1.54231: Flags [F.], seq 10, ack 2, win 512, options [nop,nop,TS val 1700334660 ecr 1700334659], length 0
0x0000: 4500 0034 77fc 4000 4006 c4c5 7f00 0001
0x0010: 7f00 0001 c5ee d3d7 0ea6 d482 807f 9dbe
0x0020: 8011 0200 fe28 0000 0101 080a 6559 0c44
0x0030: 6559 0c43
/**** 第四次挥手 ****/
IP 127.0.0.1.54231 > 127.0.0.1.50670: Flags [.], ack 11, win 512, options [nop,nop,TS val 1700334660 ecr 1700334660], length 0
0x0000: 4500 0034 4302 4000 4006 f9bf 7f00 0001
0x0010: 7f00 0001 d3d7 c5ee 807f 9dbe 0ea6 d483
0x0020: 8010 0200 fe28 0000 0101 080a 6559 0c44
0x0030: 6559 0c44
从上面报文可以看到紧急标志U和urg3和seq4可以看出数据流的第6个字符c被当做带外数据,并且带外数据会截断正常数据,123ab和后面的正常数据123不能被一个recv调用读出全部数据。