linux C语言socket函数recv

news2024/9/24 9:26:31

recv 函数是在 Linux C 语言网络编程中用于从已连接的套接字接收数据的函数。它通常与 TCP 连接一起使用,但也可以用于 UDP(尽管对于 UDP,更常使用 recvfrom,因为它还可以接收发送方的地址信息)。

函数原型

recv 函数在 <sys/socket.h> 中定义,其函数原型如下:

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

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数

  1. sockfd
    这是一个已打开的套接字描述符,它标识了要从其接收数据的网络连接。对于 TCP,这个套接字通常是通过 socket 函数创建的,并且已经通过 connect 函数与远程服务器建立了连接,或者通过 accept 函数接受了来自客户端的连接。

  2. buf
    这是一个指向缓冲区的指针,该缓冲区用于存储从套接字接收到的数据。在调用 recv 函数之前,应确保该缓冲区有足够的空间来存储要接收的数据。

  3. len
    这是缓冲区 buf 的长度,以字节为单位。它指定了缓冲区中可以存储的最大数据量。

  4. flags
    这是一个整数值,用于传递特殊的接收标志给底层协议。这些标志可以修改 recv 函数的行为。通常,这个参数被设置为 0,表示使用标准的接收行为。然而,一些可能的标志包括:

    • MSG_PEEK:查看数据,但不从套接字的接收队列中移除。
    • MSG_WAITALL:等待直到接收到完整的 len 字节数据,或者发生错误。然而,这个标志的行为可能因实现而异,并且不建议在阻塞模式下使用。
    • MSG_OOB:仅接收带外数据(out-of-band data)。
    • MSG_DONTWAIT:非阻塞模式操作(等效于使用非阻塞套接字)。
    • MSG_ERRQUEUE:获取扩展的错误信息(较少使用)。

返回值

  • 如果成功,recv 函数返回实际接收到的字节数。这个数字可能小于 len 参数指定的长度,这取决于发送方发送的数据量、套接字的接收缓冲区中的数据量以及网络条件。
  • 如果连接已正常关闭,recv 函数返回 0。
  • 如果出现错误,recv 函数返回 -1,并设置全局变量 errno 以指示错误类型。

错误处理

当 recv 函数返回 -1 时,可以检查 errno 来确定错误的原因。一些常见的错误包括:

  • EWOULDBLOCK 或 EAGAIN:套接字是非阻塞的,并且没有数据可供立即接收。
  • ECONNRESET:连接被对端重置。
  • ENOTCONN:套接字未连接到远程地址。
  • EINTR:接收操作被中断,通常是因为接收到了一个信号。
  • EBADF:提供的套接字描述符不是有效的或不支持接收操作。

注意事项

  1. 阻塞与非阻塞:根据套接字的配置,recv 函数可以表现为阻塞或非阻塞。在阻塞模式下,recv 会等待直到有数据可以接收或发生错误。在非阻塞模式下,如果没有数据可供接收,recv 会立即返回 EWOULDBLOCK 或 EAGAIN 错误。

  2. 多次接收:由于 TCP 的流性质,一次 recv 调用可能不会接收到发送方发送的所有数据。因此,可能需要多次调用 recv 来接收完整的消息或数据流。

  3. 数据边界recv 函数不保证按发送方发送的原始边界接收数据。应用程序需要自己处理消息的边界问题,通常通过在消息前加上长度字段或使用特定的分隔符。

  4. 关闭连接:当对端关闭连接时,recv 函数将返回 0,表示没有更多的数据可以接收。这是正常关闭连接的指示。

  5. 性能考虑:与 send 类似,频繁地接收小块数据可能不如一次性接收大块数据高效。应用程序应优化数据传输以提高性能。

在使用 recv 函数时,应处理可能的错误和异常情况,并确保正确地管理套接字和数据缓冲区。

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main() {
    // 假定 sockfd 是已经连接好的套接字
    int sockfd = /* socket(...) */;
    
    // 用于存储接收数据的缓冲区
    char buffer[1024];
    
    // 清空缓冲区
    memset(buffer, 0, sizeof(buffer));
    
    // 接收数据
    int bytes_received = recv(sockfd, buffer, sizeof(buffer), 0);
    if (bytes_received < 0) {
        // 处理错误
        perror("recv failed");
    } else if (bytes_received == 0) {
        // 对方已经关闭了连接
        printf("Peer has performed an orderly shutdown\n");
    } else {
        // 打印接收到的数据
        printf("Received (%d bytes): %.*s\n", bytes_received, bytes_received, buffer);
    }
    
    // 关闭套接字
    close(sockfd);
    
    return 0;
}

在上面的代码示例中,`sockfd` 应已经是一个成功连接的 socket—这意味着在 TCP 的情况下,应该在客户端使用 connect 或在服务器端使用 accept 来获得 sockfd

在实际应用程序中,通常会将 recv 放在某个循环中以持续接收数据。当 recv 返回 0 表示对方已经关闭了连接,接收循环就应该结束。还需要处理各种可能出现的错误。

perror 函数是 C 语言中用来报告 errno 错误的常用方法。当系统调用或库函数出错时,它们通常会设置全局变量 errno 来指示错误的类型。perror 函数可以读取当前的 errno 值,并打印出一条描述该错误的消息到标准错误输出(stderr)。

perror 函数的原型如下:

void perror(const char *str);

其中 str 是一个字符串指针,它通常被用来提供关于出错上下文的额外信息。这个字符串会被打印出来,后面紧跟着一个冒号、一个空格和由 errno 值对应的错误消息。

例如,如果你调用了一个可能失败的函数(如 open),你可以立即调用 perror 来打印出任何发生的错误:

	#include <stdio.h> 
	#include <stdlib.h> 
	#include <errno.h> 
	#include <fcntl.h> 

	int main() 
    { 
	    int fd = open("nonexistent_file.txt", O_RDONLY); 
	    if (fd == -1) 
        { 
	        perror("Error opening file"); 
	        return EXIT_FAILURE; 
	    } 
	    // ... 其他代码 ... 
	    return EXIT_SUCCESS; 
	}

如果文件 nonexistent_file.txt 不存在,open 函数会失败,并设置 errno。然后 perror 会打印出类似以下的消息:

Error opening file: No such file or directory

这里,“Error opening file” 是传递给 perror 的字符串,而 “No such file or directory” 是与 errno 值对应的系统错误消息。注意,errno 的值在调用另一个可能设置 errno 的函数之前应当被认为是未定义的,除非你明确地知道它不会被改变。因此,通常在调用可能出错的函数之后立即检查 errno 并使用 perror 或其他方法来报告错误是一个好习惯。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1397648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【漏洞复现】Hikvision SPON IP网络对讲广播系统命令执行漏洞(CVE-2023-6895)

文章目录 前言声明一、系统简介二、漏洞描述三、影响版本四、漏洞复现五、修复建议 前言 Hikvision Intercom Broadcasting System是中国海康威视&#xff08;Hikvision&#xff09;公司的一个对讲广播系统。 声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播…

在 wsl-ubuntu 里通过 docker 启动 gpu-jupyter

在 wsl-ubuntu 里通过 docker 启动 gpu-jupyter 0. 背景1. 安装 docker-ce2. 安装 NVIDIA Container Toolkit3. 使用 nvidia-ctk 命令配置容器运行4. 通过 docker 运行 nvidia-smi5. 运行 gpu-jupyter6. 访问 gpu-jupyter7. 测试 gpu-jupyter 是否可以访问 cuda 0. 背景 今天突…

每日OJ题_算法_滑动窗口⑤_力扣904水果成篮

目录 力扣904. 水果成篮 解析及代码1&#xff08;使用容器&#xff09; 解析及代码2&#xff08;开数组&#xff09; 力扣904. 水果成篮 904. 水果成篮 - 力扣&#xff08;LeetCode&#xff09; 难度 中等 你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这…

stable-diffusion-webui 安装与运行

大家好&#xff0c;我是水滴~~ 本文主要介绍在各种显卡环境中&#xff0c;如何安装和运行 stable-diffusion-webui&#xff0c;包括&#xff1a;在 NVIDIA 显卡环境上安装、在 AMD 显卡环境上安装、在集显或小于 4G 显卡环境上安装。 文章目录 在 NVIDIA 显卡环境上安装下载配…

如何在业务代码中优雅使用责任链模式

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;为请求创建了一个接收者对象的链。这种模式给予请求的类型&#xff0c;对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。 在这种模式中&#xff0c;通常每个接收者都包含对另一个接收者…

LLM:RoPE位置编码

论文&#xff1a;https://arxiv.org/pdf/2104.09864.pdf 代码&#xff1a;https://github.com/ZhuiyiTechnology/roformer 发表&#xff1a;2021 绝对位置编码&#xff1a;其常规做法是将位置信息直接加入到输入中&#xff08;在x中注入绝对位置信息&#xff09;。即在计算 q…

mysql原理--锁

1.解决并发事务带来问题的两种基本方式 上一章唠叨了事务并发执行时可能带来的各种问题&#xff0c;并发事务访问相同记录的情况大致可以划分为3种&#xff1a; (1). 读-读 情况&#xff1a;即并发事务相继读取相同的记录。 读取操作本身不会对记录有一毛钱影响&#xff0c;并不…

爬虫笔记(一):实战登录古诗文网站

需求&#xff1a;登录古诗文网站&#xff0c;账号&#xff0b;密码&#xff0b;图形验证码 第一&#xff1a;自己注册一个账号&#xff0b;密码哈 第二&#xff1a;图形验证码&#xff0c;需要一个打码平台&#xff08;充钱&#xff0c;超能力power&#xff01;&#xff09;或…

“GPC爬虫池有用吗?

作为光算科技的独有技术&#xff0c;在深入研究谷歌爬虫推出的一种吸引谷歌爬虫的手段 要知道GPC爬虫池是否有用&#xff0c;就要知道谷歌爬虫这一概念&#xff0c;谷歌作为一个搜索引擎&#xff0c;里面有成百上千亿个网站&#xff0c;对于里面的网站内容&#xff0c;自然不可…

网络爬虫采集工具

在当今数字化的时代&#xff0c;获取海量数据对于企业、学术界和个人都至关重要。网络爬虫成为一种强大的工具&#xff0c;能够从互联网上抓取并提取所需的信息。本文将专心分享关于网络爬虫采集数据的全面指南&#xff0c;深入探讨其原理、应用场景以及使用过程中可能遇到的挑…

php array_diff 比较两个数组bug避坑 深入了解

今天实用array_diff出现的异常问题&#xff0c;预想的结果应该是返回 "integral_initiate">"0"&#xff0c;实际没有 先看测试代码&#xff1a; $a ["user_name">"测","see_num">0,"integral_initiate&quo…

leetCode-42.接雨水

&#x1f4d1;前言 本文主要是【算法】——算法模拟的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&#xff…

Go语言基础快速上手

1、Go语言关键字 2、Go数据类型 3、特殊的操作 3.1、iota关键字 Go中没有明确意思上的enum&#xff08;枚举&#xff09;定义&#xff0c;不过可以借用iota标识符实现一组自增常亮值来实现枚举类型。 const (a iota // 0b // 1c 100 // 100d // 100 (与上一…

H - Least Common Multiple H - 最小公倍数

题目 The least common multiple (LCM) of a set of positive integers is the smallest positive integer which is divisible by all the numbers in the set. For example, the LCM of 5, 7 and 15 is 105. 一组正整数的最小公倍数 &#xff08;LCM&#xff09; 是最小的正整…

rabbitmq的介绍、使用、案例

1.介绍 rabbitmq简单来说就是个消息中间件&#xff0c;可以让不同的应用程序之间进行异步的通信&#xff0c;通过消息传递来实现解耦和分布式处理。 消息队列&#xff1a;允许将消息发到队列&#xff0c;然后进行取出、处理等操作&#xff0c;使得生产者和消费者之间能够解耦&…

使用 Kali Linux Hydra 工具进行攻击测试和警报生成

一、Hydra 工具和 Kali Linux 简介 在网络安全领域中&#xff0c;渗透测试是评估系统密码强度的重要组成部分。Hydra 是一款由黑客组织“The Hackers Choice”开发的开源登录破解工具&#xff0c;支持50多种协议。本教程将探索如何将 Hydra 与 Kali Linux 结合使用&#xff0c…

快快销ShopMatrix 分销商城多端uniapp可编译5端 - 升级申请(可自定义申请表单)

在企业或组织中&#xff0c;升级申请通常涉及到员工职位、权限、设备或者其他资源的提升或更新。创建一个可自定义的升级申请表单可以帮助更高效地收集和处理这类申请信息。以下是一个基本的步骤&#xff1a; 确定表单字段&#xff1a; 申请人信息&#xff1a;姓名、部门、职位…

【Spring Boot 3】【Redis】基本数据类型操作

【Spring Boot 3】【Redis】基本数据类型操作 背景介绍开发环境开发步骤及源码工程目录结构 背景 软件开发是一门实践性科学&#xff0c;对大多数人来说&#xff0c;学习一种新技术不是一开始就去深究其原理&#xff0c;而是先从做出一个可工作的DEMO入手。但在我个人学习和工…

priority_queue的使用与模拟实现(容器适配器+stack与queue的模拟实现源码)

priority_queue的使用与模拟实现 引言&#xff08;容器适配器&#xff09;priority_queue的介绍与使用priority_queue介绍接口使用默认成员函数 size与emptytoppush与pop priority_queue的模拟实现构造函数size与emptytoppush与pop向上调整建堆与向下调整建堆向上调整建堆向下调…

UE5 蓝图编辑美化学习

虚幻引擎中干净整洁蓝图的15个提示_哔哩哔哩_bilibili 1.双击线段成节点。 好用&#xff0c;爱用 2.用序列节点 好用&#xff0c;爱用 3.用枚举。 好用&#xff0c;能避免一些的拼写错误 4.对齐节点 两点一水平线 5.节点上下贴节点 &#xff08;以前不懂&#xff0c;现在经常…