在之前的文章使用valgrind调试socket发送非字符串数据时的内存泄漏问题中,提到了使用sendrecv发送和接收大数据量的方法

#include <sys/types.h>
#include <sys/socket.h>

int recvall (int s,char *buf,int *len)
{
    int total = 0;
    int bytesleft = *len;
    int n;

    while (total<*len)
    {
        n= recv(s,buf+total,bytesleft,0);
        if(n==-1){break;}
        total += n;
        bytesleft -=n;
    }

    *len = total;
    return n==-1?-1:0;
}

int sendall(int s, char *buf, int *len)
{
    int total = 0;
    int bytesleft = *len; 
    int n;

    while(total < *len) {
        n = send(s, buf+total, bytesleft, 0);
        if (n == -1) { break; }
        total += n;
        bytesleft -= n;
    }

    *len = total;

    return n==-1?-1:0;
} 

但在实践过程中,发现recvall是有缺陷的。当调用recvall函数时,*len是一个大数值,total0total<*len,开始while循环,但是recv始终没有接收到数据,n = recv(s,buf+total,bytesleft,0) = 0total += ntotal始终为0,造成了while死循环。

所以应当将recvall改为以下形式

int recvall(int s, char* buf, int* len)
{
    int total = 0;
    int bytesleft = *len;
    int n;

    while ((n = recv(s, buf+ total, bytesleft, 0))>0)
    {       
        total += n;
    bytesleft -= n; 
        if(bytesleft == 0){break;}
    }
            
    return n==-1?-1:total;
}

(n = recv(s, buf+ total, bytesleft, 0))>0即接收到数据开始才启动while循环,当剩余的bytesleft的数据等于0时,退出while循环,返回total接收到的整体数据量。

在实际使用时,服务端接收到数据后,才返回数据

int nbytes = 0;
while((nbytes = recvall(sockfd,input_buffer,&need_recv))>0)
{
    // ....
    // ....
}

参考资料:

Should send() and recv() buffer size be as big as possible?

标签: none

评论已关闭