数据读写flags选项的使用-MSG_OOB

客户端代码

#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调用读出全部数据。

上一篇:SpringBoot 单元测试利器——Mockito


下一篇:Elasticsearch集群环境部署并发布