本手册页描述了 Linux 网络套接字层用户接口。 套接字是用户进程和内核中网络协议栈之间的统一接口。 协议模块分为协议族(protocol families)(如 AF_INET、AF_IPX 和 AF_PACKET)和套接字类型(socket types)(如 SOCK_STREAM 或 SOCK_DGRAM)。 有关families和types的更多信息,请参阅 socket(2) 。
用户进程使用这些函数来发送或接收数据包以及执行其他套接字 *** 作。 有关更多信息,请参阅它们各自的手册页。
socket(2) 创建套接字,connect(2) 将套接字连接到远程套接字地址,bind(2) 函数将套接字绑定到本地套接字地址,listen(2) 告诉套接字应接受新连接, accept(2) 用于获取具有新传入连接的新套接字。 socketpair(2) 返回两个连接的匿名套接字(仅为少数本地families如 AF_UNIX 实现)
send(2)、sendto(2) 和sendmsg(2) 通过套接字发送数据,而recv(2)、recvfrom(2)、recvmsg(2) 从套接字接收数据。 poll(2) 和 select(2) 等待数据到达或准备好发送数据。 此外,还可以使用 write(2)、writev(2)、sendfile(2)、read(2) 和 readv(2) 等标准 I/O *** 作来读取和写入数据。
getsockname(2) 返回本地套接字地址, getpeername(2) 返回远程套接字地址。 getsockopt(2) 和 setsockopt(2) 用于设置或获取套接字层或协议选项。 ioctl(2) 可用于设置或读取一些其他选项。
close(2) 用于关闭套接字。 shutdown(2) 关闭全双工套接字连接的一部分。
套接字不支持使用非零位置查找或调用 pread(2) 或 pwrite(2)。
通过使用 fcntl(2) 在套接字文件描述符上设置 O_NONBLOCK 标志,可以在套接字上执行非阻塞 I/O。 然后所有会阻塞的 *** 作(通常)将返回 EAGAIN( *** 作应稍后重试); connect(2) 将返回 EINPROGRESS 错误。 然后用户可以通过 poll(2) 或 select(2) 等待各种事件。
如果不使用poll(2) 和 select(2) ,还让内核通过 SIGIO 信号通知应用程序有关事件的信息。 为此,必须通过 fcntl(2) 在套接字文件描述符上设置 O_ASYNC 标志,并且必须通过 sigaction(2) 安装有效的 SIGIO 信号处理程序。 请参阅下面的信号讨论。
每个套接字域(families)都有自己的套接字地址格式,具有特定于域的地址结构。 这些结构的首字段都是整数类型的“家族”字段(类型为 sa_family_t),即指出自己的套接字域或者说是protocol families。 这允许对所有套接字域可以使用统一的系统调用(例如,connect(2)、bind(2)、accept(2)、getsockname(2)、getpeername(2)),并通过套接字地址来确定特定的域。
为了允许将任何类型的套接字地址传递给套接字 API 中的接口,定义了类型 struct sockaddr。 这种类型的目的纯粹是为了允许将特定于域的套接字地址类型转换为“通用”类型,以避免编译器在调用套接字 API 时发出有关类型不匹配的警告。
struct sockaddr 以及在AF_INET常用的地址结构struct sockaddr_in如下所示,sockaddr_in.sin_zero是占位符:
此外,套接字 API 提供了数据类型 struct sockaddr_storage。 这种类型适合容纳所有支持的特定于域的套接字地址结构; 它足够大并且正确对齐。 (特别是它足够大,可以容纳 IPv6 套接字地址。)同struct sockaddr一样,该结构体包括以下字段,可用于标识实际存储在结构体中的套接字地址的类型: sa_family_t ss_family
sockaddr_storage 结构在必须以通用方式处理套接字地址的程序中很有用(例如,必须同时处理 IPv4 和 IPv6 套接字地址的程序)。
下面列出的套接字选项可以使用setsockopt(2) 设置并使用getsockopt(2) 读取。
当写入已关闭(由本地或远程端)的面向连接的套接字时,SIGPIPE 被发送到写入进程并返回 EPIPE。 当写调用指定 MSG_NOSIGNAL 标志时,不发送信号。
当使用 FIOSETOWN fcntl(2) 或 SIOCSPGRP ioctl(2) 请求时,会在 I/O 事件发生时发送 SIGIO。 可以在信号处理程序中使用 poll(2) 或 select(2) 来找出事件发生在哪个套接字上。 另一种方法(在 Linux 2.2 中)是使用 F_SETSIG fcntl(2) 设置实时信号; 实时信号的处理程序将使用其 siginfo_t 的 si_fd 字段中的文件描述符调用。 有关更多信息,请参阅 fcntl(2)。
在某些情况下(例如,多个进程访问单个套接字),当进程对信号做出反应时,导致 SIGIO 的条件可能已经消失。 如果发生这种情况,进程应该再次等待,因为 Linux 稍后会重新发送信号。
核心套接字网络参数可以通过目录 /proc/sys/net/core/ 中的文件访问。
These operations can be accessed using ioctl(2):
error = ioctl(ip_socket, ioctl_type, &value_result)
Valid fcntl(2) operations:
Linux assumes that half of the send/receive buffer is used for internal kernel structuresthus the values in the corresponding /proc files are twice what can be observed on the wire. Linux will allow port reuse only with the SO_REUSEADDR option when this option was set both in the previous program that performed a bind(2) to the port and in the program that wants to reuse the port. This differs from some implementations (e.g., FreeBSD) where only the later program needs to set the SO_REUSEADDR option. Typically this difference is invisible, since, for example, a server program is designed to always set this option.
recv, recvfrom, recvmsg - receive a message from a socket
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 is formed by ORing one or more of the following values:
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.
recvfrom() 将接收到的消息放入缓冲区 buf 。 调用者必须在 len 中指定缓冲区的大小。
如果调用者希望拿到消息的原地址, 并且底层协议可以提供消息的源地址时,应将 src_addr 设置为指向用于接收消息原地址的缓冲区。 在这种情况下, addrlen 是一个 value-result 参数。 在调用之前,它应该被初始化为与 src_addr 关联的缓冲区的大小。 返回时,addrlen 被更新以包含源地址的实际大小。 如果提供的缓冲区太小,则截断返回的地址; 在这种情况下, addrlen 将返回一个大于提供给调用的值。
如果调用者对源地址不感兴趣,则应将 src_addr 和 addrlen 指定为 NULL。
ssize_t recv(int sockfd, void* buf, size_t len, int flags)
recv() 调用通常仅用于已连接的套接字(请参阅 connect(2))。 相当于调用:
recvfrom(fd, buf, len, flags, NULL, 0)
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags)
recvmsg() 调用使用 msghdr 结构来 最小化直接提供的参数数量 。 这个结构在 <sys/socket.h>中定义如下:
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_iov 和 msg_iovlen 描述了一个 struct iovec 类型的数组, msg_iovlen 表示数组的元素个数,而struct iovec则是描述了一个缓冲区
字段 msg_control 指向用于其他协议控制相关消息或杂项辅助数据的缓冲区。 当recvmsg()被调用时, msg_controllen 为 msg_contro l中可用缓冲区的长度; 从成功调用返回时,它将被设置为控制消息序列的长度。
控制消息的格式为:
只能通过 cmsg(3) 中定义的宏访问辅助数据。
例如,Linux 使用这种辅助数据机制通过 UNIX 域套接字传递扩展错误、IP 选项或文件描述符。 有关在各种套接字域中使用辅助数据的更多信息,请参阅 unix(7) 和 ip(7)。
msghdr 中的 msg_flags 字段在 recvmsg() 返回时设置 。 它可以包含几个标志:
这些调用返回接收到的字节数,如果发生错误,则返回 -1。 如果发生错误,则设置 errno 以指示错误。
当流套接字对等端执行有序关闭(orderly shutdown)时,返回值将为 0(传统的“文件结束”返回)。
各种域(例如 UNIX 和 Internet 域)中的数据报套接字允许零长度数据报。 当收到这样的数据报时,返回值为 0。
如果从流套接字接收的请求字节数为 0,则也可能返回值 0。
这些是套接字层生成的一些标准错误。 底层协议模块可能会产生和返回额外的错误; 查看他们的手册页。
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.
如果零长度数据报未决,则带有零标志参数的 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)。
getaddrinfo(3) 中显示了使用 recv() 的示例。
send, sendto, sendmsg - send a message on a socket
系统调用 send()、sendto() 和 sendmsg() 用于将消息传输到另一个套接字。
仅当套接字处于连接状态时才可以使用 send() 调用(以便知道预期的接收者, 也就是说send()仅仅用于数据流类型的数据发送 ,对于TCP,服务端和客户端都可以使用send/recv;但是对于UDP,只能是客户端使用send/recv,服务端只能使用sendto/recvfrom,因为客户端是进行了connect *** 作知道要发送和接受的地址)。send() 和 write(2) 之间的唯一区别是存在 flags 参数。此外,
send(sockfd, buf, len, flags)
等价于
sendto(sockfd, buf, len, flags, NULL, 0)
参数 sockfd 是发送者套接字的文件描述符。
如果在连接模式的套接字(即套接字类型为SOCK_STREAM、SOCK_SEQPACKET)上使用 sendto(),则参数 dest_addr 和 addrlen 将被忽略(当它们不是NULL和0时可能返回错误EISCONN),若套接字没有实际连接(还没有三次握手建立连接)将返回错误ENOTCONN。 否则,目标地址由 dest_addr 给出, addrlen 指定其大小。 对于 sendmsg(),目标地址由 msg.msg_name 给出, msg.msg_namelen 指定其大小。
对于 send() 和 sendto(),消息位于 buf 中,长度为 len 。 对于sendmsg(),消息存放于 msg.msg_iov 元素指向 数组数据区 (见下)中。 sendmsg() 调用还允许发送辅助数据(也称为控制信息) 。
如果消息太长而无法通过底层协议原子传递( too long to pass atomically through the underlying protocol ),则返回错误 EMSGSIZE,并且不会传输消息。
No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1.
当消息不适合套接字的发送缓冲区时,send() 通常会阻塞,除非套接字已置于非阻塞 I/O 模式。 在这种情况下,在非阻塞模式下它会失败并显示错误 EAGAIN 或 EWOULDBLOCK。 select(2) 调用可用于确定何时可以发送更多数据 。
上面的的描述还是很笼统的,以TCP为例,按我的理解,我认为只要发送缓冲区有空闲位置,且此时协议栈没有向网络发送数据,那么就可以写入,对于阻塞模式,直到所有数据写入到缓冲区,就会返回,否则一直阻塞,对于非阻塞模式,是有一个超时时间的,这个由 SO_SNDTIMEO 选项控制,详细见 socket(7) ,如果当前有空闲位置可以发即当前可写入,那么就写入到缓冲区,知道超时之前写入多少算多少,然后返回成功写入的字节数,如果超时时任何数据都没写出去,或者当前就是不可写入,那么返回-1 ,并设置errno为 EAGAIN 或 EWOULDBLOCK。
The flags argument is the bitwise OR of zero or more of the following flags.
sendmsg() 使用的 msghdr 结构的定义如下:
对于未连接的套接字 msg_name 指定数据报的目标地址,它指向一个包含地址的缓冲区; msg_namelen 字段应设置为地址的大小。 对于连接的套接字,这些字段应分别指定为 NULL 和 0。 这里的未连接指的是数据报协议,连接指的是数据流协议
The msg_iov and msg_iovlen fields specify scatter-gather locations, as for writev(2).
msg_iov是一个buffer数组:
使用 msg_control 和 msg_controllen 成员发送控制信息(辅助数据)。 内核可以处理的每个套接字最大控制缓冲区长度由 /proc/sys/net/core/optmem_max 中的值限制; 见 socket(7) 。 有关在各种套接字域中使用辅助数据的更多信息,请参阅 unix(7) 和 ip(7)。
msg_flags 字段被忽略。
成功时,返回成功发送的字节数,这个字节数并不一定和我们的缓冲区大小相同 。 出错时,返回 -1,并设置 errno 以指示错误。
这些是套接字层生成的一些标准错误。 底层协议模块可能会产生和返回额外的错误; 请参阅它们各自的手册页。
4.4BSD, SVr4, POSIX.1-2001. These interfaces first appeared in 4.2BSD.
POSIX.1-2001 describes only the MSG_OOB and MSG_EOR flags. POSIX.1-2008 adds a specification of MSG_NOSIGNAL. The MSG_CONFIRM flag is a Linux extension.
根据 POSIX.1-2001,msghdr 结构的 msg_controllen 字段应该是 socklen_t 类型,而 msg_iovlen 字段应该是 int 类型,但是 glibc 目前将两者都视为 size_t。
有关可用于在单个调用中传输多个数据报的 Linux 特定系统调用的信息,请参阅 sendmmsg(2)。
Linux may return EPIPE instead of ENOTCONN.
getaddrinfo(3) 中显示了使用 send() 的示例。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)