UNP编程:43---IO管理(recv、send函数)

一、函数原型

#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 这两个函数一般针对于TCP使用

二、参数

  • 参数1:接受数据/发送数据的fd(注意:参数1的用法与recvfrom和sendto不同)
  • 参数2、3:接受/发送的数据,以及接受/发送的字节数
  • 参数4:可为0(默认值),或是下面图中常量的逻辑或

send函数的flags

recv函数的flags

常用的选项

  • MSG_CONFIRM:指示数据链路层协议支持监听对方的回应,直到得到答复,它仅能用于SOCK_DGRAM和SOCK_RAW类型的socket
  • MSG_DONTROUTE:本标志告知内核目的主机在某个直接连接的本地网络上,因而无需执行路由表查找,直接将数据发送到本地局域网内的主机。我们已随SO_DONTROUTE套接字选项提供了本特性的额外信息。这个既可以使用MSG_DONTROUTE标志针对单个输出操作开启,也可以使用SO_DONTROUTE套接字选项针对某个给定套接字上的所有输出操作开启
  • MSG_DONTWAIT:本标志在无需打开相应套接字的非阻塞标志的前提下,把单个I/O操作临时指定为非阻塞,接着执行I/O操作,然后关闭非阻塞标志。我们将在介绍非阻塞式I/O以及如何打开或关闭某个套接字上所有I/O操作的非阻塞标志
    • 这个标志是随Net/3新增设的,可能并非所有系统都支持它
  • MSG_MORE:告诉内核应用程序还有更多数据要发送,内核将超时等待新数据写入TCP发送缓冲区后一并发送。这样可以放置TCP发送过多的报文段,从而提高传输效率
  • MSG_NOSIGNAL:往读端关闭的管道或者socket连接中写数据时不引发SIGPIPE信号
  • MSG_OOB:对于send,本标志指明即将发送带外数据。正如我们将在第24章中讲述的那样,TCP连接上只有一个字节可以作为带外数据发送。对于recv, 本标志指明即将读入的是带外数据而不是普通数据
  • MSG_PEEK:本标志适用于recv和recvfrom,它允许我们查看缓冲区中的数据,而且系统不在recv或recvfrom返回后丢弃这些数据。我们将在14.7节详细讨论这个标志
    • 当指定MSG_PEEK标志时,可以查看下一个要读取的数据但不真正取走它。当再次调用read或其中一个recv函数时,会返回刚才查看的数据
  • MSG_WAITALL:本标志随4.3BSD Reno引入。它告知内核不要在尚未读入请求数目的字 节之前让一个读操作返回
    • 即使指定了MSG_WAITALL,如果发生下列情况之一:(a)捕获一个信号, (b)连接被终止,(c)套接字发生一个错误,相应的读函数仍有可能返回比 所请求字节数要少的数据
    • 本标志随4.3BSD Reno引入。它告知内核不要在尚未读入请求数目的字 节之前让一个读操作返回。如果系统支持本标志,我们就可以省掉我们自定义的readn函数,而替之以如下的宏:
#define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL) 

  • 另有一些标志适用于TCP/IP以外的协议族。举例来说,OSI的传输层是基于记录的(不像 TCP那样是一个字节流),其输出操作支持MSG_EOR标志,指示逻辑记录的结束

三、返回值

send

  • 成功:返回实际写入的数据长度
  • 出错:返回-1并设置errno,可取的errno如下:
    • 这些是套接字层生成的一些标准错误。底层协议模块可能会产生和返回其他错误
    • EACCES:
      • 对于UNIX域套接字(由路径名标识),目标套接字文件上的写权限被拒绝,或者路径前缀中的某个目录的搜索权限被拒绝(参阅path_resolution())
      • (对于UDP套接字)尝试发送到网络/广播地址,就好像它是一个单播地址
    • EAGAIN或EWOULDBOLCK:套接字标记为非阻塞,请求的操作将阻塞。在这种情况下,POSIX.1-2001允许返回任何一个错误,并且不要求这些常量具有相同的值,因此可移植应用程序应该检查这两种可能性
    • EAGAIN:Internet域数据报套接字)sockfd引用的套接字以前没有被绑定到一个地址,当尝试将它绑定到临时端口时,它被确定临时端口范围内的所有端口号目前都在使用。参见ip中关于/proc/sys/net/ipv4/ip_local_port_range的讨论
    • EALREADY:另一个快速开放正在进行中
    • EBADF:sockfd不是一个有效的打开文件描述符
    • ECONNRESET:通过对等点重置连接
    • EDESTADDRREQ:套接字不是连接模式,没有设置对等地址
    • EFAULT:为参数指定了无效的用户空间地址
    • EINTR:在传输任何数据之前发生的信号
    • EINVAL:无效的参数传递
    • EISCONN:连接模式套接字已经连接,但是指定了一个接收方。(现在要么返回此错误,要么忽略收件人规范)
    • EMSGSIZE:套接字类型要求以原子方式发送消息,而要发送的消息的大小使得这种情况不可能发生
    • ENOBUFS:网络接口的输出队列已满。这通常表示接口已停止发送,但可能是由瞬态拥塞引起的。(通常,这在Linux中不会发生。当设备队列溢出时,数据包会无声地丢弃)
    • ENOMEM:没有可用内存
    • ENOTCONN:套接字没有连接,并且没有给定目标。
    • ENOTSOCK:文件描述符sockfd不引用套接字
    • EOPNOTSUPP:标志参数中的一些位不适合套接字类型
    • EPIPE:本地端已在面向连接的套接字上关闭。在本例中,除非设置了MSG_NOSIGNAL,否则进程还将收到一个SIGPIPE
  • 注意事项:
    • 即使send返回成功,也并不表示另一端就一定接收到数据,我们保证的只是当send成功返回时,数据已经被无错误地发送到网络驱动程序上
    • 对于支持报文边界的协议,如果尝试发送的单个报文的长度超过协议所支持的最大长度,那么send会发送失败,并设置errno为EMSGSIZE
    • 对于字节流协议,send会阻塞直到整个数据传输完成

recv

  • 成功:回实际读取到的数据长度,它可能小于我们期望的长度,因此我们可能需要多次调用recv
  • 返回0:
    • recv返回0。如果发送者已经调用shutdown来结束传输,或者网络协议支持按默认的顺序关闭并且发送端已经关闭,那么当所有的数据接收完毕后,recv会返回0
    • 不同域(例如UNIX和Internet域)中的数据报套接字允许零长度的数据报。当接收到这样的数据报时,返回值为0
    • 如果要从流套接字接收的请求字节数为0,也可以返回值0
  • 出错:返回-1并设置errno,可取的errno如下
    • EAGAIN或EWOULDBOLCK:套接字标记为非阻塞,接收操作将阻塞,或者设置了接收超时,并且在接收数据之前超时已经过期。在这种情况下,POSIX.1允许返回任何一个错误,并且不要求这些常量具有相同的值,因此可移植应用程序应该检查这两种可能性
    • EBADF:参数sockfd是一个无效的文件描述符
    • ECONNREFUSED:远程主机拒绝允许网络连接(通常是因为它没有运行所请求的服务)
    • EFAULT:接收缓冲区指针指向进程地址空间之外
    • EINTR:在任何数据可用之前,接收被信号的发送中断
    • EINVAL:无效的参数传递
    • ENOMEM:无法为recvmsg()分配内存
    • ENOTCONN:套接字与一个面向连接的协议相关联,并且还没有被连接(参阅connect()和accept())
    • ENOTSOCK:文件描述符sockfd不引用套接字

四、flags标志的注意事项

  • flags参数在设计上存在一个基本问题:它是按值传递的,而不是一个值-结果参数。因此它 只能用于从进程向内核传递标志。内核无法向进程传回标志。对于TCP/IP协议这一点不成问题, 因为TCP/IP几乎不需要从内核向进程传回标志
  • 然而随着OSI协议被加到4.3BSD Reno中,却提出了随输入操作向进程返送MSG_EOR标志的需求。4.3BSD Reno做出的决定是保持常用输入函数 (recv和recvfrom)的参数不变,而改变recvmsg和sendmsg所用的msghdr结构,在msghdr结构中新增了一个整数msg_flags成员,而且既然该结构按引用传递,内核就可以在返回时修改这些标志。这个决定同时意味着如果一个进程需要由内核更新标志,它就必须调用 recvmsg,而不是调用recv或recvfrom
  • recvmsg、sendmsg函数请参阅:https://blog.csdn.net/qq_41453285/article/details/89810683

、演示案例(MSG_OOB选项)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值