socket不完整传输的后续处理

75 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情



回想一下之前我讲过的send()函数,我当时说过,send()可能不会一下子把你所有的数据都发送出去,比如你想放一个长度为512字节的字符串,send()的返回值却是412。你可能不禁会问到,剩下的100字节怎么办?

其实这100字节仍然在你小得可怜的缓冲区(buffer)中,等着你把他们发送出去呢!毕竟事事无法如你所愿,内核也会有自己的小脾气,有时就是不想把你的数据一下子发送出去,你还得自己动手把剩下的数据发送出去。

你可以这么写:

#include <sys/types.h>
#include <sys/socket.h>
​
int sendall(int s, char *buf, int *len)
{
    int total = 0;        // how many bytes we've sent
    int bytesleft = *len; // how many we have left to send
    int n;
​
    while(total < *len) {
        n = send(s, buf+total, bytesleft, 0);
        if (n == -1) { break; }
        total += n;
        bytesleft -= n;
    }
​
    *len = total; // return number actually sent here
​
    return n==-1?-1:0; // return -1 on failure, 0 on success
} 

上例中,s是你想发送数据的socketbuf是保存数据的缓冲区(buffer),len指向一个int类型的变量,这个变量记录了缓冲区剩余数据的大小。

send()异常时会返回-1,并且最终实际发送的字节数量保存在了len变量中。sendall()会竭尽全力发送你所有的数据,除非发生了错误会导致立即返回,否则len的值一定就是你想发送的数据的长度。

为了完整性,给一个使用sendall()函数的例子:

char buf[10] = "Beej!";
int len;
​
len = strlen(buf);
if (sendall(s, buf, &len) == -1) {
    perror("sendall");
    printf("We only sent %d bytes because of the error!\n", len);
} 

当部分数据包到达时,接收器端会发生什么?

如果数据包是可变长度的,接收方如何知道一个数据包何时结束,另一个何时开始?

现实世界的情景百出往往最让我们头疼。你必须得使用封装(忘记这个概念的话点我)来解决这个问题喽。

下文见!