基于TCP下MSG_PEEK的套接字接受缓冲区的排队数据量分析

来源:互联网 发布:c51单片机跑马灯程序 编辑:程序博客网 时间:2024/05/29 16:58

如何获取已经排队的数据量:

(1)、获取套接字当中的数据量的目的是为了避免读操作而堵塞在内核中(这样会堵塞整个程序的进行), 为了解决这个问题, 我们可以使用非堵塞IO

(2)、在recv、recvfrom、recvnsg函数当中的flags参数标志,我们可以使用MSG_PEEK标志,仅仅读取该套接字当中缓冲区当中的数据量,但是并不真真的读取该数据,也可以使用MSG_DONTWAIT | MSG_PEEK相结合。但是我们需要注意的是,(针对tcp)可能两次调用recv函数返回的值不同,因为两次调用函数之间可能会数据到来。就针对UDP套接字而言,前一次调用recvfrom函数加上MSG_PEEK标志查看接收对列的数据量,后一次不加该标志调用recvfrom函数读取数据,那么两次的返回值(数据报大小、内容、发报者地址)将会是完全相同。

(3)、一些支持ioctl的FIONREAD命令。改命令第三个值-结果参数也会指向某个整数的一个指针,内核通过该整数返回的值就是套接字接收对列里面当前所有数据的字节数;而对于UDP而言,就是所有的已排队数据报的总和的字节数大小。因为针对UDP中返回值包括Ip地址和端口号(IPv4是16字节,IPv6是24字节)。


TCP连接的条件下 代码如下

客户端核心代码片段如下:

#include "unp.h"void str_cli(FILE *fp, int sockfd){    int maxfdp, stdineof = 0;    char sendbuf[MAXLINE], recvbuf[MAXLINE];    fd_set rset;    FD_ZERO(&rset);    int num;    for(;;){        if(stdineof == 0) FD_SET(fileno(fp), &rset);        FD_SET(sockfd, &rset);        maxfdp = fileno(fp);        if((num = Select(maxfdp + 1, &rset, NULL, NULL, NULL)) < 0){            if(errno == EINTR) {                fprintf(stdout, "semaphore lead to system call\n");                continue;            }else{                fprintf(stdout, "select error\n");            }        }        if(FD_ISSET(sockfd, &rset)){            if(Readline(sockfd, recvbuf, MAXLINE) <= 0){                if(stdineof == 1){                    return;                }                if(errno == EINTR){                    fprintf(stdout, "system call interrupted\n");                    continue;                }else{                    fprintf(stdout, "read error\n");                }            }            fprintf(stdout, "read error\n");            Fputs(recvbuf, stdout);        }        if(FD_ISSET(fileno(fp), &rset)){            if(Fgets(sendbuf, MAXLINE, fp) == NULL){                FD_CLR(fileno(fp), &rset);                Shutdown(sockfd, SHUT_WR);                stdineof = 1;                continue;            }            Writen(sockfd, sendbuf, strlen(sendbuf));        }    }}
代码分析:我相信自己看得懂


tcp服务器端核心代码如下

#include "unp.h"void _str_echo(int sockfd){    char recvbuf[MAXLINE];    int n;    for(;;){        n = Recv(sockfd, recvbuf, MAXLINE, MSG_PEEK);        if(0 == n) break;       //server close connect        else{            int npend;            sleep(1);            Ioctl(sockfd, FIONREAD, &npend);            fprintf(stdout, "%d bytes from PEEK, %d bytes pending\n", n,npend);            n = Read(sockfd, recvbuf, MAXLINE);            recvbuf[n] = 0;            Fputs(recvbuf, stdout);        }    }}
代码分析:

1、MSG_PEEK会把数据读到缓冲区,但是并不会清理套接字中的数据,还可以供其他进程读取。

2、ioctl的FIONREAD也可以读取套接字中缓冲区的数据。


运行结果如下:


阅读全文
0 0
原创粉丝点击