本文共 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
- #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
-
-
-
-
-
-
-
-
-
-
- int Init_sockaddr(struct sockaddr_in *stru, const int protoc, const char *addr,const unsigned int port)
- {
- if (stru == NULL || addr == NULL)
- return -1;
-
-
- if (inet_addr(addr) == INADDR_NONE)
- return -1;
-
-
- 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;
- }
-
-
-
-
-
-
-
- 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;
-
-
- 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;
- }
-
-
-
-
-
-
-
-
- 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)
- {
-
- 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;
- }
-
-
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- return -1;
-
-
- if (bind(sockfd, (SA*)&saddr, sizeof(saddr)) == -1)
- {
- close(sockfd);
- return -1;
- }
-
-
- 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;
-
- r = recv(clifd, buf, sizeof(buf), MSG_PEEK);
- cout << "接收队列中可读的数据长度:" << r << endl;
- cout << "buf:" << buf << endl;
- r = recv(clifd, buf, sizeof(buf), 0);
- cout << "读取长度:" << r << endl;
- cout << "buf:" << buf << endl;
- return 0;
- }
执行结果