日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MSG_PEEK标志

發布時間:2023/11/30 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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标志的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。