send(2) - Linux 手册页

名称

send, sendto, sendmsg - 在套接字上发送消息

概要

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

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

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

描述

系统调用 send()、sendto() 和 sendmsg() 用于向另一个套接字传输消息。

send() 调用仅可在套接字处于 已连接 状态(以便已知预期的接收者)时使用。send() 和 write(2) 之间的唯一区别是 flags(标志)参数的存在。当 flags 参数为零时,send() 等同于 write(2)。此外,以下调用

send(sockfd, buf, len, flags);

等同于

sendto(sockfd, buf, len, flags, NULL, 0);

参数 sockfd 是发送套接字的文件描述符。

如果在面向连接的套接字(SOCK_STREAM, SOCK_SEQPACKET)上使用 sendto(),则参数 dest_addraddrlen 会被忽略(如果它们不为 NULL 且不为 0,可能会返回 EISCONN 错误),如果套接字实际上未连接,则会返回 ENOTCONN 错误。否则,目标的地址由 dest_addr 提供,其大小由 addrlen 指定。对于 sendmsg(),目标的地址由 msg.msg_name 提供,其大小由 msg.msg_namelen 指定。

对于 send() 和 sendto(),消息位于 buf 中,长度为 len。对于 sendmsg(),消息由数组 msg.msg_iov 的元素指向。sendmsg() 调用还允许发送辅助数据(也称为控制信息)。

如果消息太长而无法通过底层协议原子地传输,则会返回 EMSGSIZE 错误,且消息不会被发送。

send() 中不包含传递失败的隐式指示。局部检测到的错误通过返回 -1 来表示。

当消息无法放入套接字的发送缓冲区时,send() 通常会阻塞,除非套接字已被设置为非阻塞 I/O 模式。在非阻塞模式下,此时会失败并报错 EAGAINEWOULDBLOCKselect(2) 调用可用于确定何时可以发送更多数据。

flags 参数是以下零个或多个标志的按位或(bitwise OR)。

MSG_CONFIRM (自 Linux 2.3.15 起)
通知链路层前向进度已发生:您收到了来自对方的成功回复。如果链路层未收到此信号,它将定期重新探测邻居(例如,通过单播 ARP)。仅在 SOCK_DGRAMSOCK_RAW 套接字上有效,目前仅为 IPv4 和 IPv6 实现。详情请参阅 arp(7)。
MSG_DONTROUTE
不使用网关发送数据包,仅发送到直接连接网络上的主机。这通常仅由诊断或路由程序使用。这仅针对支持路由的协议族定义;数据包套接字不支持。
MSG_DONTWAIT (自 Linux 2.2 起)
启用非阻塞操作;如果操作会被阻塞,则返回 EAGAINEWOULDBLOCK(这也可以通过使用 F_SETFL fcntl(2) 设置 O_NONBLOCK 标志来启用)。
MSG_EOR (自 Linux 2.2 起)
终止记录(当支持此概念时,例如 SOCK_SEQPACKET 类型的套接字)。
MSG_MORE (自 Linux 2.4.4 起)
调用者还有更多数据要发送。此标志与 TCP 套接字一起使用,可获得与 TCP_CORK 套接字选项(参见 tcp(7))相同的效果,区别在于此标志可以按调用进行设置。

自 Linux 2.6 起,UDP 套接字也支持此标志,它通知内核将所有设置了此标志的调用所发送的数据打包成一个数据报,只有在执行不指定此标志的调用时才会传输该数据报。(另请参阅 udp(7) 中描述的 UDP_CORK 套接字选项。)

MSG_NOSIGNAL (自 Linux 2.2 起)
请求在面向流的套接字上出现错误时,如果对方中断连接,则不发送 SIGPIPE。但仍会返回 EPIPE 错误。
MSG_OOB
在支持此概念的套接字(例如 SOCK_STREAM 类型)上发送 带外 (out-of-band) 数据;底层协议也必须支持 带外 数据。
msghdr 结构的定义如下。有关其字段的准确描述,请参阅 recv(2) 及以下内容。
struct msghdr {
    void         *msg_name;       /* optional address */
    socklen_t     msg_namelen;    /* size of address */
    struct iovec *msg_iov;        /* scatter/gather array */
    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_controlmsg_controllen 成员发送控制信息。内核可处理的最大控制缓冲区长度受限于每个套接字在 /proc/sys/net/core/optmem_max 中的值;请参阅 socket(7)。

返回值

成功时,这些调用返回发送的字符数。出错时,返回 -1,并相应地设置 errno

错误

以下是套接字层生成的一些标准错误。底层协议模块可能会生成并返回其他错误;请参阅它们各自的手册页。

EACCES

(对于由路径名标识的 UNIX 域套接字) 拒绝了目标套接字文件的写权限,或者路径前缀中的某个目录拒绝了搜索权限。(请参阅 path_resolution(7)。)

(对于 UDP 套接字) 尝试将网络/广播地址当作单播地址进行发送。
EAGAINEWOULDBLOCK
套接字被标记为非阻塞,且请求的操作将会阻塞。POSIX.1-2001 允许在此情况下返回任一错误,且不要求这些常量具有相同的值,因此可移植的应用程序应检查这两种可能性。
EBADF

指定了无效的描述符。

ECONNRESET
连接被对方重置。
EDESTADDRREQ
套接字不是面向连接的,且未设置对等地址。
EFAULT

为参数指定了无效的用户空间地址。

EINTR

在传输任何数据之前发生了信号;请参阅 signal(7)。

EINVAL

传递了无效参数。

EISCONN
面向连接的套接字已连接,但指定了接收者。(现在要么返回此错误,要么忽略接收者指定。)
EMSGSIZE
套接字类型要求以原子方式发送消息,而要发送的消息大小使其无法实现。
ENOBUFS
网络接口的输出队列已满。这通常表明接口已停止发送,但也可能是由瞬时拥塞引起的。(通常,这种情况在 Linux 中不会发生。当设备队列溢出时,数据包会被静默丢弃。)
ENOMEM

没有可用内存。

ENOTCONN
套接字未连接,且未指定目标。
ENOTSOCK
参数 sockfd 不是一个套接字。
EOPNOTSUPP
flags 参数中的某些位对于该套接字类型是不恰当的。
EPIPE

面向连接套接字的本地端已被关闭。在这种情况下,进程还将收到 SIGPIPE,除非设置了 MSG_NOSIGNAL

符合

4.4BSD, SVr4, POSIX.1-2001。这些函数调用出现在 4.2BSD 中。

POSIX.1-2001 仅描述了 MSG_OOBMSG_EOR 标志。POSIX.1-2008 增加了对 MSG_NOSIGNAL 的规范。MSG_CONFIRM 标志是 Linux 扩展。

说明

上述原型遵循单一 UNIX 规范(Single UNIX Specification),glibc2 也是如此;在 4.x BSD 中,flags 参数是 int 类型,但在 libc4 和 libc5 中是 unsigned int;在 4.x BSD 和 libc4 中,len 参数是 int 类型,但在 libc5 中是 size_t;在 4.x BSD、libc4 和 libc5 中,addrlen 参数是 int 类型。另请参阅 accept(2)。

根据 POSIX.1-2001,msghdr 结构的 msg_controllen 字段类型应为 socklen_t,但 glibc 目前将其定为 size_t

有关可在单次调用中传输多个数据报的 Linux 特定系统调用的信息,请参阅 sendmmsg(2)。

错误

Linux 可能会返回 EPIPE 而不是 ENOTCONN

示例

getaddrinfo(3) 中展示了 sendto() 的使用示例。

参见

fcntl(2), getsockopt(2), recv(2), select(2), sendfile(2), sendmmsg(2), shutdown(2), socket(2), write(2), cmsg(3), ip(7), socket(7), tcp(7), udp(7)

引用自

forward(1), gnutls_transport_set_push_function(3), netwrite(3), pth(3), select_tut(2), sockatmark(3), socketcall(2), splice(2), tevent_queue_tutorial(3), unix(7), xinetd.conf(5)