博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
recv_MSG_peek
阅读量:4114 次
发布时间:2019-05-25

本文共 4041 字,大约阅读时间需要 13 分钟。

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

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

客户程序

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

服务器程序

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

执行结果

你可能感兴趣的文章
element-ui全局自定义主题
查看>>
facebook库runtime.js
查看>>
vue2.* 中 使用socket.io
查看>>
openlayers安装引用
查看>>
js报错显示subString/subStr is not a function
查看>>
高德地图js API实现鼠标悬浮于点标记时弹出信息窗体显示详情,点击点标记放大地图操作
查看>>
初始化VUE项目报错
查看>>
vue项目使用安装sass
查看>>
HTTP和HttpServletRequest 要点
查看>>
在osg场景中使用GLSL语言——一个例子
查看>>
关于无线PCB中 中50欧姆的特性阻抗的注意事项
查看>>
Spring的单例模式源码小窥
查看>>
后台服务的变慢排查思路(轻量级应用服务器中测试)
查看>>
MySQL中InnoDB事务的默认隔离级别测试
查看>>
微服务的注册与发现
查看>>
bash: service: command not found
查看>>
linux Crontab 使用 --定时任务
查看>>
shell编程----目录操作(文件夹)
查看>>
机器学习-----K近邻算法
查看>>
HBASE安装和简单测试
查看>>