recv

xiaoxiao2021-02-28  243

转载自:

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]  view plain  copy  print ? #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   客户程序

[cpp]  view plain  copy  print ? #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;   }  

服务器程序

[cpp]  view plain  copy  print ? #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;   }  

执行结果

转载请注明原文地址: https://www.6miu.com/read-18347.html

最新回复(0)