linux C语言socket函数recv

2024-01-20 10:12
文章标签 语言 linux 函数 socket recv

本文主要是介绍linux C语言socket函数recv,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 或其他方法来报告错误是一个好习惯。

这篇关于linux C语言socket函数recv的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/625669

相关文章

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Go语言中Recover机制的使用

《Go语言中Recover机制的使用》Go语言的recover机制通过defer函数捕获panic,实现异常恢复与程序稳定性,具有一定的参考价值,感兴趣的可以了解一下... 目录引言Recover 的基本概念基本代码示例简单的 Recover 示例嵌套函数中的 Recover项目场景中的应用Web 服务器中

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流