recv/send 和 recvmsg/sendmsg 函数

阅读更多
        recv 和 send 函数类似于标准的 read 和 wirte 函数,不过多了一个额外的参数。
#include 
ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);
ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);
                          /* 返回值:若成功则为读入或写出的字节数,否则为 -1 */

        这两个函数的前三个参数等同于 read 和 write 的 3 个参数,flags 参数的值或为 0,或为下表中的一个或多个常值的逻辑或。
recv/send 和 recvmsg/sendmsg 函数_第1张图片
        其中各标志选项的含义如下。
        * MSG_DONTROUTE:告知内核目的主机在某个直接连接的本地网络上,而无需查找路由表。这可使用本标志针对单个输出操作开启,也可使用 SO_DONTROUTE 套接字选项(见 通用套接字选项)针对某个给定套接字上的所有输出操作开启。
        * MSG_DONTWAIT:临时将当个 I/O 操作指定为非阻塞。
        * MSG_OOB:对于 send,表示即将发送带外数据;对于 recv,表示即将读入的是带外数据。后面会讲到,TCP 连接上只有一个字节可以作为带外数据发送。
        * MSG_PEEK:适用于 recv 和 recvfrom 函数,它允许我们查看已可读取的数据,而且系统不会在 recv 或 recvfrom 返回后丢弃这些数据。
        * MSG_WAITALL:告知内核不要在尚未读入请求数目的字节前让一个读操作返回。当然,当(a)捕获一个信号,(b)连接被终止,(c)套接字发生错误时仍有可能返回比所请求的字节数要少的数据。
        另有一些标志适用于 TCP/IP 以外的协议族,比如 OSI 的传输层是基于记录的(TCP 是基于字节流),其输出操作支持 MSG_EOR 标志,用于指示逻辑记录的结束。
        最后,这两个函数的 flags 参数都是按值传递的,内核无法向进程传回标志,因此如果一个进程需要由内核更新标志,它就必须调用更为通用的 recvmsg 和 sendmsg 函数。
#include 
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);
                       /* 返回值:若成功则为读入或写出的字节数,否则为 -1 */
struct msghdr{
    void           *msg_name;        // protocol address
    socklen_t      msg__namelen;     // size of protocol address
    struct iovec   *msg_iov;         // scatter/gather array
    int            msg_iovlen;       // # elements in msg_iov
    void           *msg_control;     // ancillary data (cmsghdr struct)
    socklen_t      msg_controllen;   // length of ancillary data
    int            msg_flags;        // flags returned by recvmsg()
};

        在 msghdr 结构的成员变量之中:
        msg_name 和 msg_namelen 用于套接字未连接的场合(如未连接的 UDP 套接字),msg_name 指向一个套接字地址结构,用来存放接收者(对于 sendmsg)或发送者(对于 recvmsg)的协议地址。如果无需指明协议地址(如对于 TCP 或已连接 UDP 套接字),应将其置为空指针。msg_namelen 对于 sendmsg 是一个值参数,对于 recvmsg 则是一个值-结果参数,表示协议地址的长度。
        msg_iov 和 msg_iovlen 用于指定输入或输出缓冲区数组,类似于 readv 或 writev 的第二个和第三个参数(见 readv/writev 函数及存储映射 I/O)。msg_control 和 msg_controllen 用于指定可选的辅助数据的位置和大小,这会在后面介绍。
        这里还需要区分 recvmsg 和 sendmsg 的 flags 参数和 msghdr 结构的 msg_flags 成员。
        1、只有 recvmsg 使用 msg_flags 成员。在调用 recvmsg 时,flags 参数会被复制到 msg_flags 成员,并由内核使用其值驱动接收处理过程。内核还依据 recvmsg 的结果更新 msg_flags 成员的值。
        2、sendmsg 会忽略 msg_flags 成员,因为它直接使用 flags 参数驱动发送处理过程。这意味着如果想在某个 sendmsg 调用中设置 MSG_DONTWAIT 等标志,要设置的应该是 flags 参数,而非 msg_flags 成员。
        下表汇总了内核为输入和输出函数检查的 flags 参数值以及 recvmsg 可能返回的 msg_flags 成员值。
recv/send 和 recvmsg/sendmsg 函数_第2张图片
        其中,内核只检查而不返回前 4 个标志,既检查又返回接下来的 2 个标志,不检查而只返回后 4 个标志。recvmsg 返回的 7 个标志解释如下。
        * MSG_BCAST:它的返回条件是本数据报作为链路层广播收取或者其目的 IP 地址是一个广播地址。它是比用 IP_RECVDSTADDR 套接字选项来判定一个 UDP 数据报是否发往某个广播地址的更好方法。
        * MSG_MCAST:它的返回条件是本数据报作为链路层多播收取。
        * MSG_TRUNC:它的返回条件是本数据报被截断,即内核预备返回的数据超过进程事先分配的空间(所有 iov_len 成员之和)。
        * MSG_CTRUNC:它的返回条件是本数据报的辅助数据被截断,即内核预备返回的辅助数据超过进程事先分配的空间(msg_controllen)。
        * MSG_EOR:它的返回条件是返回数据结束一个逻辑记录。
        * MSG_OOB:它绝不为 TCP 带外数据返回,用于其他协议族(如 OSI)。
        * MSG_NOTIFICATION:它由 SCTP 接收者返回,指示读入的消息是一个事件通知,而不是数据消息。
  • recv/send 和 recvmsg/sendmsg 函数_第3张图片
  • 大小: 13.6 KB
  • recv/send 和 recvmsg/sendmsg 函数_第4张图片
  • 大小: 25.8 KB
  • 查看图片附件

你可能感兴趣的:(socket,recv,send,recvmsg,sendmsg)