c语言 recvbuf

99ANYc3cd6
预计阅读时长 18 分钟
位置: 首页 C语言 正文

recvbuf 并不是一个 C 语言标准库中的函数或关键字,它是一个变量名,通常是程序员在调用网络编程中的 recv()recvfrom() 函数时,用来接收数据的那块缓冲区(buffer)的名称。

c语言 recvbuf
(图片来源网络,侵删)

recvbuf 就是一个你定义的字符数组或指针,用来存放从网络另一端接收到的数据。


recvbuf 的核心概念

当你使用 recv() 函数接收数据时,你需要提供一个内存空间(即缓冲区)来存放这些数据。recvbuf 就是这个缓冲区的变量名。

recv() 函数的原型如下:

#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

这里的 buf 参数就是你传入的 recvbuf

c语言 recvbuf
(图片来源网络,侵删)
  • sockfd: 你要读取数据的套接字描述符。
  • buf: 指向一个缓冲区的指针,这个缓冲区就是 recvbuf,它必须有足够的空间来存放接收到的数据。
  • len: buf 指向的缓冲区的长度,这决定了 recv() 一次最多能读取多少字节的数据。
  • flags: 通常设置为 0,表示使用默认行为。

如何定义和使用 recvbuf

下面我们通过一个完整的客户端/服务器例子来展示 recvbuf 的用法。

场景:客户端发送一条消息,服务器接收并打印。

服务器端代码 (server.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024 // 定义缓冲区大小
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char recvbuf[BUFFER_SIZE] = {0}; // <--- 这里就是我们的 recvbuf
    // 1. 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    // ... (省略 socket 配置、bind、listen 等代码) ...
    // 2. 接受连接
    printf("Waiting for a connection...\n");
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    printf("Connection accepted from %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
    // 3. 从客户端接收数据
    // recvbuf 被用来存储接收到的数据
    // sizeof(recvbuf) 告诉 recv 函数,recvbuf 的大小是 1024 字节
    int valread = read(new_socket, recvbuf, BUFFER_SIZE); 
    // 注意: 在 TCP 流套接字上,read() 和 recv() 通常可以互换使用。
    // 更规范的做法是使用 recv(new_socket, recvbuf, BUFFER_SIZE, 0);
    printf("Message from client: %s\n", recvbuf);
    // 4. 关闭套接字
    close(new_socket);
    close(server_fd);
    return 0;
}

客户端代码 (client.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *message = "Hello from client!";
    // ... (省略创建套接字、连接服务器的代码) ...
    // 发送消息
    send(sock, message, strlen(message), 0);
    printf("Message sent to server\n");
    // 关闭套接字
    close(sock);
    return 0;
}

recvbuf 的重要注意事项

a) 缓冲区大小 (BUFFER_SIZE) 的选择

recvbuf 的大小非常关键。

  • 太小: 如果服务器发送的数据超过了 BUFFER_SIZErecv() 函数在一次调用中只能读取 BUFFER_SIZE 大小的数据,剩余的数据会留在操作系统的接收缓冲区中,等待下一次 recv() 调用,你需要在一个循环中反复调用 recv() 直到所有数据都接收完毕。
  • 太大: 会浪费内存。

如何处理大数据? 如果数据大小不确定,通常的做法是循环接收,直到 recv() 返回 0(表示连接已关闭)或小于 0(表示出错)。

char recvbuf[BUFFER_SIZE];
int total_bytes_received = 0;
int bytes_received;
while ((bytes_received = recv(new_socket, recvbuf + total_bytes_received, BUFFER_SIZE - 1, 0)) > 0) {
    total_bytes_received += bytes_received;
    // 检查是否已经接收完所有数据,或者是否需要继续接收
    // ...
}
recvbuf[total_bytes_received] = '\0'; // 确保字符串以 '\0' 结尾

b) 字符串终止符 (\0)

上面的例子中,recvbuf 被定义为 char recvbuf[BUFFER_SIZE] = {0};{0} 会将整个数组初始化为 0,也就是空字符 \0,这确保了即使接收到的数据不是一个完整的 C 字符串(比如没有结尾的 \0),printf("%s", recvbuf) 也不会越界打印,因为它会在遇到第一个 \0 时停止。

如果你接收的是二进制数据(而不是文本字符串),就不能依赖 \0,并且需要非常小心地处理缓冲区边界。

c) recv() 的返回值

recv() 的返回值至关重要,你必须检查它:

  • 返回值 > 0: 表示成功接收到了的数据字节数,这个值可能小于你请求的 len
  • 返回值 == 0: 表示对端已经关闭了连接,这是正常结束的信号。
  • 返回值 < 0: 表示发生了错误,最常见的是 EAGAINEWOULDBLOCK(在非阻塞模式下,表示没有数据可读),或者 ECONNRESET(连接被重置)。

错误处理示例:

int valread = recv(new_socket, recvbuf, BUFFER_SIZE, 0);
if (valread > 0) {
    // 数据接收成功
    recvbuf[valread] = '\0'; // 手动添加字符串结束符
    printf("Received: %s\n", recvbuf);
} else if (valread == 0) {
    printf("Client disconnected.\n");
} else {
    // perror 会打印具体的错误信息,如 "Connection reset by peer"
    perror("recv failed"); 
}

recvbuf vs. sendbuf

recvbuf 相对的是 sendbuf,它们的概念是对称的:

  • recvbuf: 用于接收数据的缓冲区,是 recv() 函数的输入参数。
  • sendbuf: 用于发送数据的缓冲区,是 send()write() 函数的输入参数。
// sendbuf 示例
char sendbuf[] = "This is a message to be sent.";
send(sock_fd, sendbuf, strlen(sendbuf), 0);

特性 描述
本质 recvbuf 是一个变量名,通常是一个字符数组或指针。
用途 作为 recv()read() 函数的参数,用来存放从网络接收到的原始数据。
定义 char recvbuf[BUFFER_SIZE];char *recvbuf = malloc(BUFFER_SIZE);
大小 大小 (BUFFER_SIZE) 需要精心设计,以避免数据截断或内存浪费。
返回值处理 必须检查 recv() 的返回值,以确定实际接收了多少字节,以及连接状态(成功/关闭/错误)。
字符串安全 如果处理文本,记得手动添加 \0 终止符,并确保不会发生缓冲区溢出。
循环接收 对于不确定大小的数据,通常需要在一个循环中调用 recv() 直到所有数据接收完毕。

理解 recvbuf 的工作原理是掌握 C 语言网络编程的基础,它就是一块用来“接住”网络数据的内存区域。

-- 展开阅读全文 --
头像
织梦网站栏目管理空白,如何解决?
« 上一篇 04-13
织梦CMS标签生成器如何快速创建标签?
下一篇 » 04-13

相关文章

取消
微信二维码
支付宝二维码

目录[+]