You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

send()函数缓冲区长度与返回值不匹配及超大长度发送处理问询

关于send()函数的两个常见问题解答

嘿,我来帮你理清这两个网络编程里关于send()的常见疑问,都是容易踩坑的点:

1. 如何处理send()函数中缓冲区长度输入与返回值大小不匹配的问题?

首先得明白为什么会出现这种不匹配:send()的返回值是实际成功发送的字节数,它不一定等于你传入的length参数——比如内核的发送缓冲区满了、网络拥塞,或者连接状态有变化,都会导致send()只能发送部分数据就返回。

处理这种情况的核心思路是循环发送,直到所有数据都发完或者出现不可恢复的错误,具体步骤可以参考下面的逻辑:

  • 维护一个remaining变量,记录还没发送的字节数,初始值就是你要发送的总长度;
  • 维护一个buf_ptr指针,指向当前要发送的缓冲区起始位置;
  • 每次调用send()后,检查返回值:
    • 如果返回值>0:更新remaining减去返回值,buf_ptr往后移动对应字节数;如果remaining变成0,就说明发送完成;
    • 如果返回值==-1:先检查错误码,如果是EINTR(调用被信号中断),可以重试send();如果是其他错误(比如ECONNRESET连接被重置、EBADF无效套接字),就停止发送并处理错误。

给你个简单的代码示例:

ssize_t send_all(int sock, const void *buf, size_t total_len, int flags) {
    size_t remaining = total_len;
    const char *buf_ptr = buf;
    while (remaining > 0) {
        ssize_t sent = send(sock, buf_ptr, remaining, flags);
        if (sent == -1) {
            if (errno == EINTR) {
                // 被信号中断,重试
                continue;
            } else {
                // 致命错误,返回-1
                return -1;
            }
        }
        remaining -= sent;
        buf_ptr += sent;
    }
    // 全部发送完成,返回总长度
    return total_len;
}

2. 当执行ssize_t retval = send(sock, buf, SIZE_MAX, 0);时,send()会如何处理?

先明确几个关键的类型值:SIZE_MAX是无符号类型size_t的最大值(比如64位系统是2^64-1,32位是2^32-1),而SSIZE_MAX是有符号类型ssize_t的最大值(64位是2^63-1,32位是2^31-1),确实是SIZE_MAX的一半左右(同宽度的无符号和有符号类型)。

关于这个问题的关键点:

  • send()不会自行限制发送的字节数为SSIZE_MAX。当你传入SIZE_MAX作为length时,内核会尝试发送这么多数据,但受限于实际的内核发送缓冲区大小,第一次send()最多只能发送缓冲区可用空间的字节数(这个数值远小于SIZE_MAX);
  • 但如果真的出现了极端情况(比如内核缓冲区足够大,能一次性发送超过SSIZE_MAX的字节数),send()的返回值就会出问题:因为实际发送的字节数是无符号的size_t类型,而返回值要存在有符号的ssize_t里,当数值超过SSIZE_MAX时,会发生有符号整数溢出,最终返回一个负数——这会让你误以为发送失败,但实际上可能已经发送了大量数据;
  • 所以绝对不要给send()传入超过SSIZE_MAX的length值,最好在调用前就把length限制在SSIZE_MAX以内,避免这种溢出导致的错误判断。

内容的提问来源于stack exchange,提问作者work.bin

火山引擎 最新活动