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
- #ifndef MY_NET_H
- #define MY_NET_H
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <time.h>
- #include <string.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <errno.h>
- #include <signal.h>
- #include <iostream>
- #include <sys/stat.h>
- #include <fcntl.h>
- using namespace std;
- #define SA struct sockaddr
- /*
- *Init_sockaddr 初始化地址结构
- *stru 指向地址结构的指针
- *protoc 要采用的地址族
- *addr ip地址,不能为INADDR_ANY
- *port 端口号
- *返回值:成功返回0,出错返回-1
- *提示:不对protoc(地址族)参数进行检查
- */
- int Init_sockaddr(struct sockaddr_in *stru, const int protoc, const char *addr,const unsigned int port)
- {
- if (stru == NULL || addr == NULL)
- return -1;
- /*ip地址格式不正确*/
- if (inet_addr(addr) == INADDR_NONE)
- return -1;
- /*端口超出65535*/
- if (port > 65535)
- return -1;
- bzero((void*)stru, sizeof(*stru));
- stru->sin_family = protoc;
- (stru->sin_addr).s_addr = inet_addr(addr);
- stru->sin_port = htons(port);
- return 0;
- }
- /*
- *tcp_connect 建立一个TCP套接字并连接到指定ip地址的指定端口(阻塞版本,connect会一直阻塞,直到到达默认超时时间)
- *addr ip地址
- *port 端口
- *返回值:连接成功返回描述符,出错返回-1
- */
- int Tcp_connect(const char *addr,const unsigned int port)
- {
- int sockfd;
- struct sockaddr_in saddr;
- /*参数不合法*/
- if((Init_sockaddr(&saddr, AF_INET, addr, port)) == -1)
- return -1;
- /*socket异常*/
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- return -1;
- /*连接不成功或超时*/
- if(connect(sockfd, (SA*)&saddr, sizeof(saddr)) == -1)
- {
- close(sockfd);
- return -1;
- }
- return sockfd;
- }
- /*
- *tcp_listen 建立一个套接字,并且绑定,监听
- *addr 要绑定的ip地址 INADDR_ANY或ipv4地址
- *port 要监听的端口
- *backlog listen函数的监听排队数
- *返回值:成功返回套接字描述符,出错返回-1
- */
- int Tcp_listen(const char *addr,const unsigned int port,const int backlog)
- {
- int sockfd;
- struct sockaddr_in saddr;
- if (addr == NULL)
- return -1;
- if (strcmp(addr, "INADDR_ANY") == 0)
- {
- /*端口超出65535*/
- if (port > 65535)
- return -1;
- /*排队数不合法*/
- if (backlog < 0)
- return -1;
- bzero((void*)&saddr, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl(INADDR_ANY);
- saddr.sin_port = htons(port);
- }
- else
- {
- /*参数不合法*/
- if (Init_sockaddr(&saddr, AF_INET, addr, port) == -1)
- return -1;
- }
- /*socket异常*/
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- return -1;
- /*bind*/
- if (bind(sockfd, (SA*)&saddr, sizeof(saddr)) == -1)
- {
- close(sockfd);
- return -1;
- }
- /*listen*/
- if (listen(sockfd, backlog) == -1)
- {
- close(sockfd);
- return -1;
- }
- return sockfd;
- }
- #endif
客户程序
- #include <iostream>
- #include "net.h"
- using namespace std;
- int main()
- {
- int sockfd;
- sockfd = Tcp_connect("127.0.0.1", 9999);
- if (sockfd == -1)
- {
- cout << "Tcp_connect error" << endl;
- return -1;
- }
- char send_buf[] = "Hello Server";
- char *p = send_buf;
- int r;
- int count = 0;
- while (1)
- {
- r = write(sockfd, p, strlen(p));
- if (r == -1)
- {
- perror("write error");
- return -1;
- }
- p += r;
- count += r;
- if (count == strlen(send_buf))
- break;
- }
- while(1);
- return 0;
- }
服务器程序
- #include <iostream>
- #include <unistd.h>
- #include "net.h"
- using namespace std;
- int main()
- {
- int sockfd;
- sockfd = Tcp_listen("INADDR_ANY", 9999, 5);
- if (sockfd == -1)
- {
- cout << "Tcp_listen error" << endl;
- return -1;
- }
- int clifd;
- if ((clifd = accept(sockfd, NULL, NULL)) == -1)
- {
- cout << "accept error" << endl;
- return -1;
- }
- cout << "有新连接" << endl;
- //确保客户端有数据发送到服务端(本地测试可行)
- sleep(5);
- char buf[100];
- int r;
- //利用MSG_PEEK标志读取套接子接收队列中可读的数据长度,
- r = recv(clifd, buf, sizeof(buf), MSG_PEEK);
- cout << "接收队列中可读的数据长度:" << r << endl;//此处"Hello Server"的长度为12,由于采用tcp,不一定所有数据都会到达服务端,所以值应<=12
- cout << "buf:" << buf << endl;
- r = recv(clifd, buf, sizeof(buf), 0);
- cout << "读取长度:" << r << endl; //该长度可能会大于上一个recv返回的长度,因为在此期间可能又有来自客户的数据到达
- cout << "buf:" << buf << endl;
- return 0;
- }
执行结果
MSG_PEEK标志相关推荐
- linux socket recv函数 MSG_PEEK标志介绍
考虑下面的场景,server向client发送数据"_META_DATA_\r\n_USER_DATA_",要求"\r\n"之前的数据_META_DATA_在第 ...
- Linux 并发服务器雏形总结
如下介绍一个并发回射客户端/服务器的雏形,所谓回射:就是客户端输入一条数据,服务器端读取并显示,然后服务器端再把刚读取的信息发送回客户端进行显示.示意图如下: 所谓并发服务器:就是一个服务器可以同时为 ...
- linux tcp阻塞socket recv接收数据 未达到指定长度返回问题
一直以为在阻塞的tcp socket上使用read/recv读取的数据长度一定和指定的读取长度一致,但是实际测试时发现往往返回的长度都比指定长度短,查找资料发现其实是一直误解了这个函数. 引用& ...
- 0729------Linux网络编程----------使用 select 、poll 和 epoll 模型 编写客户端程序
1.select 模型 1.1 select 函数原型如下,其中 nfds 表示的描述符的最大值加1(因为这里是左闭右开区间),中间三个参数分别表示要监听的不同类型描述符的集合,timeout用来表示 ...
- Linux五种IO模型性能分析
转载:http://blog.csdn.net/jay900323/article/details/18141217 Linux五种IO模型性能分析 目录(?)[-] 概念理解 Linux下的 ...
- 第2章 基本的TCP套接字
2.1 IPv4 TCP客户端 4个步骤: (1) socket()创建TCP套接字(window下要用初始化套接字环境) (2) connect()建立到达服务起的连接 (3) send() ...
- 《APUE》中的函数整理
第1章 unix基础知识 1. char *strerror(int errnum) 该函数将errnum(就是errno值)映射为一个出错信息字符串,返回该字符串指针.声明在string.h文件中. ...
- Linux socket 流模式(STREAM)跟数据报模式(DGRAM)的区别
"TCP是一种流模式的协议,UDP是一种数据报模式的协议", 文章目录 1.TCP 2.UDP 3.为什么 1.TCP 打个比方比喻TCP,你家里有个蓄水池,你可以里面倒水,蓄水池 ...
- CVE-2016-10229分析
漏洞描述 Linux kernel是美国Linux基金会发布的操作系统Linux所使用的内核.Linux kernel 4.5之前的版本中的udp.c文件存在安全漏洞,Linux内核中的udp.c允许 ...
最新文章
- Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.2. The Python language
- codeforce 603B - Moodular Arithmetic
- Jira 6.0.5的详细安装及汉化授权
- 谈.Net委托与线程——解决窗体假死
- C开源hash代码uthash的用法总结(1)
- xml模块、项目开发过程
- MapInfo地图投影的添加
- Java—计算长方体、四棱锥的表面积和体积
- java定义一个接口shape_定义一个借口shape
- 南阳oj S + T
- [网站推荐] 百度识图
- [Java][Casssandra] create column family in Casssandra version 1.1.7
- 我的世界pe服务器坐标怎么显示,我的世界手机版坐标怎么看 PE版没有MOD怎么查看坐标...
- python敲七游戏代码_酒桌上的游戏
- Linux快速安装Python3.6 - 邱乘屹的个人技术博客
- 什么是3D摄影机,与普通摄影机有什么不同?
- mysql以及DBeaver的使用
- Android 实现一个简单的文件下载工具
- Android实现生词本
- Butter Knife 黄油刀
热门文章
- websocket原理
- 排序算法之(7)——堆排序
- 程序猿果真有前端后端client吗
- 总结get和post区别
- jquery的动画学习--jquery权威指南
- yum update Transaction Check Error
- 使用ACE_SOCK_SEQPACK_Association获取socket连接的本地及远程IP端口信息
- C语言反序输出英文句子,C++实现英文句子中的单词逆序输出的方法
- xml mysql 模糊查询_mybatis+Spring mysql的模糊查询问题
- rpm -e --nodeps_微课 | rpm的思维导图