MSG_PEEK标志

https://blog.csdn.net/aspnet_lyc/article/details/28937229

MSG_PEEK标志可以用来读取套接字接收队列中可读的数据,一些情况会用到它,比如为了避免不阻塞而先检查套接字接收队列中可读的数据长度,再采取相应操作。
当然,不阻塞也可采取其他的方法,例如非阻塞式I/O。

MSG_PEEK标志会将套接字接收队列中的可读的数据拷贝到缓冲区,但不会使套接子接收队列中的数据减少,常见的是:例如调用recv或read后,导致套接字接收队列中的数据被读取后而减少,而指定了MSG_PEEK标志,可通过返回值获得可读数据长度,并且不会减少套接字接收缓冲区中的数据,所以可以供程序的其他部分继续读取。

注意:假设指定MSG_PEEK标志,以一个长度为1024字节的缓冲区对一个TCP套接字调用recv,返回100,如果再次调用recv,返回值可能超过100,因为两次调用之间可能有新的数据到达,导致长度增加。

下面是一个客户-服务程序,客户向服务端发送"Hello Server",服务器端指定MSG_PEEK标志获得可读的长度后,并再次调用不指定MSG_PEEK的recv读取,两次读取都能得到数据,因为指定了MSG_PEEK后套接字接收缓冲区不会减少。


net.h

  1. #ifndef MY_NET_H
  2. #define MY_NET_H
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <arpa/inet.h>
  8. #include <unistd.h>
  9. #include <time.h>
  10. #include <string.h>
  11. #include <sys/select.h>
  12. #include <sys/time.h>
  13. #include <errno.h>
  14. #include <signal.h>
  15. #include <iostream>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. using namespace std;
  19. #define SA struct sockaddr
  20. /*
  21. *Init_sockaddr 初始化地址结构
  22. *stru 指向地址结构的指针
  23. *protoc 要采用的地址族
  24. *addr ip地址,不能为INADDR_ANY
  25. *port 端口号
  26. *返回值:成功返回0,出错返回-1
  27. *提示:不对protoc(地址族)参数进行检查
  28. */
  29. int Init_sockaddr(struct sockaddr_in *stru, const int protoc, const char *addr,const unsigned int port)
  30. {
  31. if (stru == NULL || addr == NULL)
  32. return -1;
  33. /*ip地址格式不正确*/
  34. if (inet_addr(addr) == INADDR_NONE)
  35. return -1;
  36. /*端口超出65535*/
  37. if (port > 65535)
  38. return -1;
  39. bzero((void*)stru, sizeof(*stru));
  40. stru->sin_family = protoc;
  41. (stru->sin_addr).s_addr = inet_addr(addr);
  42. stru->sin_port = htons(port);
  43. return 0;
  44. }
  45. /*
  46. *tcp_connect 建立一个TCP套接字并连接到指定ip地址的指定端口(阻塞版本,connect会一直阻塞,直到到达默认超时时间)
  47. *addr ip地址
  48. *port 端口
  49. *返回值:连接成功返回描述符,出错返回-1
  50. */
  51. int Tcp_connect(const char *addr,const unsigned int port)
  52. {
  53. int sockfd;
  54. struct sockaddr_in saddr;
  55. /*参数不合法*/
  56. if((Init_sockaddr(&saddr, AF_INET, addr, port)) == -1)
  57. return -1;
  58. /*socket异常*/
  59. if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  60. return -1;
  61. /*连接不成功或超时*/
  62. if(connect(sockfd, (SA*)&saddr, sizeof(saddr)) == -1)
  63. {
  64. close(sockfd);
  65. return -1;
  66. }
  67. return sockfd;
  68. }
  69. /*
  70. *tcp_listen 建立一个套接字,并且绑定,监听
  71. *addr 要绑定的ip地址 INADDR_ANY或ipv4地址
  72. *port 要监听的端口
  73. *backlog listen函数的监听排队数
  74. *返回值:成功返回套接字描述符,出错返回-1
  75. */
  76. int Tcp_listen(const char *addr,const unsigned int port,const int backlog)
  77. {
  78. int sockfd;
  79. struct sockaddr_in saddr;
  80. if (addr == NULL)
  81. return -1;
  82. if (strcmp(addr, "INADDR_ANY") == 0)
  83. {
  84. /*端口超出65535*/
  85. if (port > 65535)
  86. return -1;
  87. /*排队数不合法*/
  88. if (backlog < 0)
  89. return -1;
  90. bzero((void*)&saddr, sizeof(saddr));
  91. saddr.sin_family = AF_INET;
  92. saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  93. saddr.sin_port = htons(port);
  94. }
  95. else
  96. {
  97. /*参数不合法*/
  98. if (Init_sockaddr(&saddr, AF_INET, addr, port) == -1)
  99. return -1;
  100. }
  101. /*socket异常*/
  102. if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  103. return -1;
  104. /*bind*/
  105. if (bind(sockfd, (SA*)&saddr, sizeof(saddr)) == -1)
  106. {
  107. close(sockfd);
  108. return -1;
  109. }
  110. /*listen*/
  111. if (listen(sockfd, backlog) == -1)
  112. {
  113. close(sockfd);
  114. return -1;
  115. }
  116. return sockfd;
  117. }
  118. #endif

客户程序

  1. #include <iostream>
  2. #include "net.h"
  3. using namespace std;
  4. int main()
  5. {
  6. int sockfd;
  7. sockfd = Tcp_connect("127.0.0.1", 9999);
  8. if (sockfd == -1)
  9. {
  10. cout << "Tcp_connect error" << endl;
  11. return -1;
  12. }
  13. char send_buf[] = "Hello Server";
  14. char *p = send_buf;
  15. int r;
  16. int count = 0;
  17. while (1)
  18. {
  19. r = write(sockfd, p, strlen(p));
  20. if (r == -1)
  21. {
  22. perror("write error");
  23. return -1;
  24. }
  25. p += r;
  26. count += r;
  27. if (count == strlen(send_buf))
  28. break;
  29. }
  30. while(1);
  31. return 0;
  32. }

服务器程序

  1. #include <iostream>
  2. #include <unistd.h>
  3. #include "net.h"
  4. using namespace std;
  5. int main()
  6. {
  7. int sockfd;
  8. sockfd = Tcp_listen("INADDR_ANY", 9999, 5);
  9. if (sockfd == -1)
  10. {
  11. cout << "Tcp_listen error" << endl;
  12. return -1;
  13. }
  14. int clifd;
  15. if ((clifd = accept(sockfd, NULL, NULL)) == -1)
  16. {
  17. cout << "accept error" << endl;
  18. return -1;
  19. }
  20. cout << "有新连接" << endl;
  21. //确保客户端有数据发送到服务端(本地测试可行)
  22. sleep(5);
  23. char buf[100];
  24. int r;
  25. //利用MSG_PEEK标志读取套接子接收队列中可读的数据长度,
  26. r = recv(clifd, buf, sizeof(buf), MSG_PEEK);
  27. cout << "接收队列中可读的数据长度:" << r << endl;//此处"Hello Server"的长度为12,由于采用tcp,不一定所有数据都会到达服务端,所以值应<=12
  28. cout << "buf:" << buf << endl;
  29. r = recv(clifd, buf, sizeof(buf), 0);
  30. cout << "读取长度:" << r << endl; //该长度可能会大于上一个recv返回的长度,因为在此期间可能又有来自客户的数据到达
  31. cout << "buf:" << buf << endl;
  32. return 0;
  33. }

执行结果




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++的单例模式与线程安全单例模式(懒汉/饿汉)

https://www.cnblogs.com/qiaoconglovelife/p/5851163.html1 教科书里的单例模式我们都很清楚一个简单的单例模式该怎样去实现&#xff1a;构造函数声明为private或protect防止被外部函数实例化&#xff0c;内部保存一个private static的类指针保存唯一的实例&#xff0c;实例的…

计算矩阵的逆和行列式的值(高斯消元+LU分解)

计算矩阵的逆 选主元的高斯消元法 朴素的高斯消元法是将矩阵A和单位矩阵放在一起&#xff0c;通过行操作&#xff08;或者列操作&#xff09;将A变为单位矩阵&#xff0c;这个时候单位矩阵就是矩阵A的逆矩阵。从上到下将A变为上三角矩阵的复杂度为O(n3n^3n3)&#xff0c;再从下…

Linux网络编程——tcp并发服务器(epoll实现)

https://blog.csdn.net/lianghe_work/article/details/46551871通过epoll实现tcp并发回执服务器&#xff08;客户端给服务器发啥&#xff0c;服务器就给客户端回啥&#xff09; 代码如下&#xff1a;#include <string.h>#include <stdio.h>#include <stdlib.h&g…

证明AVL树的上界和下界

对于n个节点的AVL树&#xff0c;其高度最低的时候肯定为叶子节点只在最后一层和倒数第二层的时候。即对于2k−1<n≦2k1−12^k-1< n\leqq 2^{k1}-12k−1<n≦2k1−1的时候下界都为kkk。因此下界为h┌log2(n1)┐−1h\ulcorner log_2(n1)\urcorner-1h┌log2​(n1)┐−1 对…

浅谈dup和dup2的用法

https://blog.csdn.net/u012058778/article/details/78705536一、dup和dup2函数 这两个函数都可以来复制一个现有的文件描述符&#xff0c;他们的声明如下&#xff1a;#include <unistd.h>int dup(int fd);int dup2(int fd, int fd 2); 123 关于dup函数&#xff0c;当我…

C++ cin 实现循环读入

习惯了使用while(~scanf("%d",x)){}来实现循环读入&#xff0c;但是有时候使用泛型编程的时候就必须使用C中的cin&#xff0c;但是当我想要实现循环读入的时候却发现有些困难。 我们可以看一下下面这个简单的例子&#xff1a; #include <iostream>using name…

BFPTR算法详解+实现+复杂度证明

BFPTR算法是由Blum、Floyed、Pratt、Tarjan、Rivest这五位牛人一起提出来的&#xff0c;其特点在于可以以最坏复杂度为O(n)O(n)O(n)地求解top−ktop-ktop−k问题。所谓top−ktop-ktop−k问题就是从一个序列中求解其第k大的问题。 top−ktop-ktop−k问题有许多解决方法&#xff…

随机化快速排序+快速选择 复杂度证明+运行测试

对于快速排序和快速选择我之前的文章已经有详细的说明&#xff0c;需要了解的同学可以移步 传送门&#xff1a;快速排序&#xff5c;快速选择(BFPTR) 所谓随机化其实就是选择枢纽的时候使用随机数选择而已&#xff0c;实现起来很简单。但是我们使用随机数如何保证复杂度呢&am…

【Linux基础】Linux的5种IO模型详解

引入 为了更好的理解5种IO模型的区别&#xff0c;在介绍IO模型之前&#xff0c;我先介绍几个概念 1.进程的切换 &#xff08;1&#xff09;定义 为了控制进程的执行&#xff0c;内核必须有能力挂起正在CPU上运行的进程&#xff0c;并恢复以前挂起的某个进程的执行。即从用户…

计算机网络【五】广播通信+以太网

局域网的拓扑 广域网使用点到点通信 局域网使用广播通信 可以随意向网络中添加设备。 总线网星形网&#xff0c;使用集线器。现在多使用星形网络。环状网树形网 其中匹配电阻用来吸收总线上传播的信号。 共享通信媒体 静态划分信道 频分复用、时分复用、波分复用、码分复用…

聊聊Linux 五种IO模型

一篇《聊聊同步、异步、阻塞与非阻塞》已经通俗的讲解了&#xff0c;要理解同步、异步、阻塞与非阻塞重要的两个概念点了&#xff0c;没有看过的&#xff0c;建议先看这篇博文理解这两个概念点。在认知上&#xff0c;建立统一的模型。这样&#xff0c;大家在继续看本篇时&#…

操作系统【四】分页存储管理

连续分配方式的缺点&#xff1a; 固定分区分配&#xff1a;缺乏灵活性&#xff0c;产生大量的内部碎片&#xff0c;内存的利用率较低 动态分区分配&#xff1a;会产生许多外部碎片&#xff0c;虽然可以用紧凑技术处理&#xff0c;但是紧凑技术的时间代价较高 基本分页存储管理…

操作系统【五】分段内存管理+段页式内存管理

基本分段存储管理 与分页最大的区别&#xff1a;离散分配时所分配地址空间的基本单位不同 进程的地址空间&#xff1a;按照程序自身的逻辑关系划分为若干个段&#xff0c;每个段都有一个段名&#xff0c;每段从0开始编址 内存分配规则&#xff1a;以段位单位进行分配&#xff…

计算机网络【六】网络层协议

网络层负责在不同网络之间尽力转发数据包&#xff08;基于数据包的IP地址转发&#xff09;。不负责丢失重传&#xff0c;也不负责顺序&#xff08;每一个数据包都是单独选择路径&#xff09;。 可靠传输是由传输层实现。 网络设备和OSI参考模型 通过分层&#xff0c;屏蔽了…

计算机网络【3】网络层

主要任务时把分组从源端发送到目的端&#xff0c;为分组交换网上的不同主机提供服务。网络层传输单位是数据报 功能&#xff1a; 路由选择与分组转发&#xff08;最佳路径 &#xff09;异构网络互联拥塞控制 数据交换方式 电路交换&#xff1a;通信时延小、有序传输、没有冲…

Linux探秘之用户态与内核态

https://www.cnblogs.com/bakari/p/5520860.html 一、 Unix/Linux的体系架构 如上图所示&#xff0c;从宏观上来看&#xff0c;Linux操作系统的体系架构分为用户态和内核态&#xff08;或者用户空间和内核&#xff09;。内核从本质上看是一种软件——控制计算机的硬件资源&…

哈夫曼算法证明+哈夫曼编码译码程序实现

哈夫曼算法证明 哈夫曼算法是一种贪心算法&#xff0c;我们考虑证明其最优子结构和贪心选择性质&#xff1a; 最优子结构&#xff1a;假设一个树是哈夫曼树&#xff0c;则以其任意节点为根节点的最大子树也是哈夫曼树。 证明&#xff1a;子树的根节点的值是其所有叶子节点出现…

Python3小知识

对于迭代器对象&#xff0c;Python默认赋值是将引用赋值&#xff0c;即指向同一片内存空间。为了实现对内存空间的赋值&#xff0c;我们可以使用分片进行深复制。例如&#xff1a; 当定义元组的时候&#xff0c;我们一般使用小括号将元素包围起来&#xff0c;也可以不使用括号…

汇编:实现日历星期数查询工具

编制一个简单日历查询工具&#xff0c;输入年、月、日&#xff0c;能够判断当日的星期数&#xff0c;并进行输出&#xff0c;数据的输入和结果的输出要有必要的提示&#xff0c;且提示独占一行。 查阅资料 ​ 经过查阅资料&#xff0c;发现有两个相关的算法可以解决这个问题&…

Linux C 实现一个简单的线程池

https://www.cnblogs.com/GyForever1004/p/9185240.html 线程池的定义 线程池是一种多线程处理形式&#xff0c;处理过程中将任务添加到队列&#xff0c;然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小&#xff0c;以默认的优先级…