好好活就是有意义的事,有意义的事就是好好活
linux手册翻译  recv(2)
linux手册翻译 recv(2)

linux手册翻译 recv(2)

recv(2) – Linux manual page (man7.org)

\color{#A00000}{NAME}

recv, recvfrom, recvmsg – receive a message from a socket

\color{#A00000}{SYNOPSIS}
#include <sys/socket.h>

ssize_t recv(int sockfd, void* buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void* restrict buf, size_t len, int flags,
                 struct sockaddr* restrict src_addr,
                 socklen_t* restrict addrlen);
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
\color{#A00000}{DESCRIPTION}

recv()、recvfrom() 和 recvmsg() 调用用于从套接字接收消息。 它们可用于在UDP和TCP的套接字上接收数据。 本页首先介绍了所有三个系统调用的共同特点,然后介绍了调用之间的区别。

recv() 和 read(2) 之间的唯一区别是flags的存在。 使用零标志参数,recv() 通常等效于 read(2) (但请参阅 NOTES),且
recv(sockfd, buf, len, flags);
等价于
recvfrom(sockfd, buf, len, flags, NULL, NULL);

所有三个调用都在成功完成时返回消息的长度。 如果消息太长而无法放入提供的缓冲区,则可能会丢弃多余的字节,具体取决于接收消息的套接字类型,显然TCP是不可能丢弃的。

如果套接字上没有可用消息,则接收调用将等待消息到达,除非套接字是非阻塞的(请参阅 fcntl(2)),在这种情况下,将返回值 -1 并将 errno 设置为 EAGAIN 或 EWOULDBLOCK。 recv_()调用通常会返回任何可用的数据,只要拿到数据就会立马返回,最多返回指定缓冲区大小的数据,但是并不会等待到让缓冲区满,除非设置了MSG_WAITALL标志,见下。

应用程序可以使用 select(2)、poll(2) 或 epoll(7) 来确定更多数据何时到达。

The flags argument

The flags argument is formed by ORing one or more of the following values:

  • MSG_CMSG_CLOEXEC
    使用 SCM_RIGHTS 操作(在 unix(7) 中描述)为通过 UNIX 域文件描述符接收的文件描述符设置 close-on-exec 标志。 出于与 open(2) 的 O_CLOEXEC 标志相同的原因,此标志很有用。
  • MSG_DONTWAIT
    启用非阻塞操作; 如果操作会阻塞,则调用将失败并显示错误 EAGAIN 或 EWOULDBLOCK。 这提供了与设置 O_NONBLOCK 标志类似的行为(通过 fcntl(2) F_SETFL 操作),但不同之处在于 MSG_DONTWAIT 是每次调用的选项,而 O_NONBLOCK 是打开文件描述上的设置(请参阅 open(2)), 这将影响调用进程中的所有线程以及保存引用相同打开文件描述的文件描述符的其他进程。
  • MSG_ERRQUEUE
    This flag specifies that queued errors should be received from the socket error queue. The error is passed in an ancillary message with a type dependent on the protocol (for IPv4 IP_RECVERR). The user should supply a buffer of sufficient size. See cmsg(3) and ip(7) for more information. The payload of the original packet that caused the error is passed as normal data via msg_iovec. The original destination address of the datagram that caused the error is supplied via msg_name.
    The error is supplied in a sock_extended_err structure:
#define SO_EE_ORIGIN_NONE    0
#define SO_EE_ORIGIN_LOCAL   1
#define SO_EE_ORIGIN_ICMP    2
#define SO_EE_ORIGIN_ICMP6   3

struct sock_extended_err
{
    uint32_t ee_errno;   /* Error number */
    uint8_t  ee_origin;  /* Where the error originated */
    uint8_t  ee_type;    /* Type */
    uint8_t  ee_code;    /* Code */
    uint8_t  ee_pad;     /* Padding */
    uint32_t ee_info;    /* Additional information */
    uint32_t ee_data;    /* Other data */
    /* More data may follow */
};

struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);

ee_errno contains the errno number of the queued error. ee_origin is the origin code of where the error originated. The other fields are protocol-specific. The macro SOCK_EE_OFFENDER returns a pointer to the address of the network object where the error originated from given a pointer to the ancillary message. If this address is not known, the sa_family member of the sockaddr contains AF_UNSPEC and the other fields of the sockaddr are undefined. The payload of the packet that caused the error is passed as normal data.
For local errors, no address is passed (this can be checked with the cmsg_len member of the cmsghdr). For error receives, the MSG_ERRQUEUE flag is set in the msghdr. After an error has been passed, the pending socket error is regenerated based on the next queued error and will be passed on the next socket operation.

  • MSG_OOB
    This flag requests receipt of out-of-band data that would not be received in the normal data stream. Some protocols place expedited data at the head of the normal data queue, and thus this flag cannot be used with such protocols.
  • MSG_PEEK
    此标志导致接收操作从接收队列的开头返回数据,而不从队列中删除该数据。 因此,随后的接收调用将返回相同的数据。
  • MSG_TRUNC
    For raw (AF_PACKET), Internet datagram (since Linux 2.4.27/2.6.8), netlink (since Linux 2.6.22), and UNIX datagram (since Linux 3.4) sockets: return the real length of the packet or datagram, even when it was longer than the passed buffer.
  • MSG_WAITALL
    此标志请求操作阻塞,直到满足完整请求(即接收的数据充满自己的指定的缓冲区大小)。 但是,如果捕获到信号、发生错误或断开连接,或者要接收的下一个数据的类型与返回的数据类型不同(数据类型指的是??),则调用返回的数据仍可能少于请求的数据。 此标志对数据报套接字无效

recvfrom()

size_t recvfrom(int sockfd, void* restrict buf, size_t len, int flags,
                 struct sockaddr* restrict src_addr,
                 socklen_t* restrict addrlen);

recvfrom() 将接收到的消息放入缓冲区 buf。 调用者必须在 len 中指定缓冲区的大小。

如果调用者希望拿到消息的原地址, 并且底层协议可以提供消息的源地址时,应将 src_addr 设置为指向用于接收消息原地址的缓冲区。 在这种情况下, addrlen 是一个 value-result 参数。 在调用之前,它应该被初始化为与 src_addr 关联的缓冲区的大小。 返回时,addrlen 被更新以包含源地址的实际大小。 如果提供的缓冲区太小,则截断返回的地址; 在这种情况下, addrlen 将返回一个大于提供给调用的值。

如果调用者对源地址不感兴趣,则应将 src_addr 和 addrlen 指定为 NULL。

recv()

ssize_t recv(int sockfd, void* buf, size_t len, int flags);
recv() 调用通常仅用于已连接的套接字(请参阅 connect(2))。 相当于调用:
recvfrom(fd, buf, len, flags, NULL, 0);

recvmsg()

ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
recvmsg() 调用使用 msghdr 结构来最小化直接提供的参数数量。 这个结构在 <sys/socket.h> 中定义如下:

struct iovec {                    /* Scatter/gather array items */
    void  *iov_base;              /* Starting address */
    size_t iov_len;               /* Number of bytes to transfer */
};
struct msghdr {
    void         *msg_name;       /* Optional address */
    socklen_t     msg_namelen;    /* Size of address */

    struct iovec *msg_iov;        /* Scatter/gather array ,struct iovec类型的数组 */
    size_t        msg_iovlen;     /* # elements in msg_iov,  数组元素个数 */

    void         *msg_control;    /* Ancillary data, see below */
    size_t        msg_controllen; /* Ancillary data buffer len */
    int           msg_flags;      /* Flags on received message */
};

msg_name 字段指向调用者分配的缓冲区,如果套接字未连接(特指UDP的服务端),则该缓冲区用于返回源地址。 调用者应在此调用之前将 msg_namelen 设置为此缓冲区的大小; 从成功调用返回后,msg_namelen 将包含返回地址的长度。 如果应用程序不需要知道源地址,可以将 msg_name 指定为 NULL。

The fields msg_iov and msg_iovlen describe scatter-gather locations, as discussed in readv(2).
需要注意的是msg_iovmsg_iovlen 描述了一个 struct iovec 类型的数组,msg_iovlen 表示数组的元素个数,而struct iovec则是描述了一个缓冲区

字段 msg_control 指向用于其他协议控制相关消息或杂项辅助数据的缓冲区。 当recvmsg()被调用时,msg_controllenmsg_control中可用缓冲区的长度; 从成功调用返回时,它将被设置为控制消息序列的长度。

控制消息的格式为:

struct cmsghdr {
    size_t cmsg_len;    /* Data byte count, including header
                                      (type is socklen_t in POSIX) */
    int    cmsg_level;  /* Originating protocol */
    int    cmsg_type;   /* Protocol-specific type */
    /* followed by
        unsigned char cmsg_data[]; */
};

只能通过 cmsg(3) 中定义的宏访问辅助数据。

例如,Linux 使用这种辅助数据机制通过 UNIX 域套接字传递扩展错误、IP 选项或文件描述符。 有关在各种套接字域中使用辅助数据的更多信息,请参阅 unix(7) 和 ip(7)。

msghdr 中的 msg_flags 字段在 recvmsg() 返回时设置。 它可以包含几个标志:

  • MSG_EOR
    表示记录结束(end-of-record;); 返回的数据完成了一条记录(通常与 SOCK_SEQPACKET 类型的套接字一起使用)。
  • MSG_TRUNC
    表示数据报的尾部被丢弃,因为数据报大于提供的缓冲区。
  • MSG_CTRUNC
    表示由于缓冲区中缺少用于辅助数据的空间,一些控制数据被丢弃。
  • MSG_OOB
    表示收到了加急或带外数据。
    (is returned to indicate that expedited or out-of-band data was received.)
  • MSG_ERRQUEUE
    表示接收到不是数据,而是来自套接字错误队列的扩展错误。
    (indicates that no data was received but an extended error from the socket error queue.)
\color{#A00000}{RETURN VALUE}

这些调用返回接收到的字节数,如果发生错误,则返回 -1。 如果发生错误,则设置 errno 以指示错误。

当流套接字对等端执行有序关闭(orderly shutdown)时,返回值将为 0(传统的“文件结束”返回)。

各种域(例如 UNIX 和 Internet 域)中的数据报套接字允许零长度数据报。 当收到这样的数据报时,返回值为 0。

如果从流套接字接收的请求字节数为 0,则也可能返回值 0。

\color{#A00000}{ERRORS}

这些是套接字层生成的一些标准错误。 底层协议模块可能会产生和返回额外的错误; 查看他们的手册页。

  • EAGAIN or EWOULDBLOCK
    非阻塞模式发生阻塞,100边了。
  • EBADF
    The argument sockfd is an invalid file descriptor.
  • ECONNREFUSED
    远程主机拒绝允许网络连接(通常是因为它没有运行请求的服务)。
  • EFAULT
    The receive buffer pointer(s) point outside the process’s address space.
  • EINTR
    The receive was interrupted by delivery of a signal before any data was available; see signal(7).
  • EINVAL
    Invalid argument passed.
  • ENOMEM
    Could not allocate memory for recvmsg().
  • ENOTCONN
    The socket is associated with a connection-oriented protocol and has not been connected (see connect(2) and accept(2)).
  • ENOTSOCK
    The file descriptor sockfd does not refer to a socket.
\color{#A00000}{CONFORMING TO}

POSIX.1-2001, POSIX.1-2008, 4.4BSD (these interfaces first appeared in 4.2BSD).

POSIX.1 describes only the MSG_OOB, MSG_PEEK, and MSG_WAITALL flags.

\color{#A00000}{NOTES}

如果零长度数据报未决,则带有零标志参数的 read(2) 和 recv() 提供不同的行为。 在这种情况下, read(2) 不起作用(数据报保持挂起),而 recv() 消耗挂起的数据报。

socklen_t 类型是由 POSIX 发明的。 另见 accept(2)

根据 POSIX.1,msghdr 结构的 msg_controllen 字段类型为 socklen_t,而 msg_iovlen 字段类型为 int,但 glibc 目前将两者设置为 size_t。

有关可用于在单个调用中接收多个数据报的 Linux 特定系统调用的信息,请参阅 recvmmsg(2)。

\color{#A00000}{EXAMPLES}

getaddrinfo(3) 中显示了使用 connect() 的示例。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注