1.查看方法
使用指令:man bind
2.详细解说(中文)
bind函数:
1.功能:
bind函数
把一个本地协议地址
赋予一个套接字
。
对于网际网协议,协议地址是32位的IPv4地址或者128位的IPv6地址与16位的TCP和UDP端口号的联合。
2.函数原型:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
3.参数说明:
1.sockfd: socket文件描述符
2.*addr: 一个指向特定协议的地址结构的指针
3.addrlen: *addr的长度
4.函数返回值:
成功: 0
失败:-1
5.bind()使用:针对TCP/IP
1.调用bind()时,可以指定一个端口号
2.调用bind()时,可以指定一个IP地址
3.调用bind()时,可以指定端口号和IP地址
4.调用bind()时,可以都不指定
下表汇总了如何根据预期的结果,选择设置sin_addr
和sin_port
或者sin6_addr
和sin6_port
IP地址 |
端口 |
结果 |
通配地址 |
0 |
内核选择IP地址和端口 |
通配地址 |
非0 |
内核选择IP地址,进程指定端口 |
本地IP地址 |
0 |
进程指定IP地址,内核指定端口 |
本地IP地址 |
非0 |
进程指定IP地址和端口 |
对于IPv4
: 通配地址由常值INADDR_ANY
来指定,其值一般为0,它告知内核去选择IP地址。如下复制语句:
struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*wildcard*/
如此复制语句对IPv4
是可行的,因为其IP地址是32位的值,可以用一个简单的数字常值表示;对于IPv6
,我们就不能这样做,因为128位的IPv6地址是存放在一个结构中,在C语言总赋值语句的右边不能是常值结构,所以我们改写为:
struct sockaddr_in6 serv;
serv.sin6_addr = in6addr_any; /*wildcard*/
系统预先分配in6addr_any
变量并将其初始化为常值IN6ADDR_ANY_INIT
。头文<netinet/in.h>中包含in6addr_any的extern声明。
无论是网络字节序还是主机字节序,INADDR_ ANY
的值(为0)都一样,因此使用htonl
并非必需。不过既然头文件<net inet/in. h>中定义的所有INADDR_
常值都是按照主机字节序定义的,我们应该对任何这些常值都使用htonl.
如果让内核来为套接字选择一个临时端口号,那么必须注意,函数bind并不返回所选择的值。实际上,由于bind函数的第二个参数有const
限定词,它无法返回所选之值。为了得到内核所选择的这个临时端口值,必须调用函数getsockname
来返回协议地址。
进程捆绑非通配IP地址到套接字上的常见例子是在为多个组织提供Web服务器的主机上。首先,每个组织都得有各自的域名,譬如这样的形式: www.organization.com.其次,每个组织的域名都映射到不同的IP地址,不过通常仍在同一个子网上。
举例来说:
如果子网是198.69.10
那么第一个组织的IP地址可以是198.69.10.128;
第二个组织的可以198.69.10.129等等。
然后,把所有这些IP地址都定义成单个网络接口的别名( 譬如在4.4BSD系统上就使用ifconfig命令的alias选项来定义),这么一来,IP层将接收所有目的地为任何一个别名地址的外来数据报。最后,为每个组织启动一个HTTP服务器的副本,每个副本仅仅捆绑相应组织的IP地址。
3.bind文档
BIND(2) Linux Programmer's Manual BIND(2)
NAME
bind - bind a name to a socket
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
DESCRIPTION 描述
When a socket is created with socket(2), it exists in a name space (address family) but has no address assigned to it. bind() assigns the address speci‐
fied by addr to the socket referred to by the file descriptor sockfd. addrlen specifies the size, in bytes, of the address structure pointed to by addr.
Traditionally, this operation is called “assigning a name to a socket”.
当使用socket(2)创建套接字时,它存在于一个名称空间(地址族)中,但没有分配给它地址。Bind()将由addr指定的地址分配给由文件描述符sockfd引用的套接字。Addrlen以字节为单
位指定addr所指向的地址结构的大小。
传统上,这个操作被称为“给套接字赋一个名称”。
It is normally necessary to assign a local address using bind() before a SOCK_STREAM socket may receive connections (see accept(2)).
在SOCK_STREAM套接字接收连接之前,通常需要使用bind()分配一个本地地址(见accept(2))。
The rules used in name binding vary between address families. Consult the manual entries in Section 7 for detailed information. For AF_INET, see ip(7);
for AF_INET6, see ipv6(7); for AF_UNIX, see unix(7); for AF_APPLETALK, see ddp(7); for AF_PACKET, see packet(7); for AF_X25, see x25(7); and for
AF_NETLINK, see netlink(7).
名称绑定中使用的规则因地址族而异。详细信息请参阅第7节中的手册条目。AF_INET,见ip(7); AF_INET6,见ipv6(7);对于AF_UNIX,参见unix(7);AF_APPLETALK,
见ddp(7);AF_PACKET,见packet(7);对于AF_X25,见x25(7);AF_NETLINK参见netlink(7)。
The actual structure passed for the addr argument will depend on the address family. The sockaddr structure is defined as something like:
为addr参数传递的实际结构将取决于地址族。sockaddr结构的定义如下:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
The only purpose of this structure is to cast the structure pointer passed in addr in order to avoid compiler warnings. See EXAMPLE below.
这个结构的唯一目的是对addr中传递的结构指针进行强制转换,以避免编译器警告。请参见下面的例子。
RETURN VALUE 返回值
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
如果成功,则返回0。在出错时,返回-1,并适当地设置errno。
ERRORS
EACCES The address is protected, and the user is not the superuser.
EACCES 地址受保护,用户不是超级用户。
EADDRINUSE
The given address is already in use.
给定地址已被使用。
EADDRINUSE
(Internet domain sockets) The port number was specified as zero in the socket address structure, but, upon attempting to bind to an ephemeral
port, it was determined that all port numbers in the ephemeral port range are currently in use. See the discussion of /proc/sys/net/ipv4/ip_lo‐
cal_port_range ip(7).
在套接字地址结构中,端口号被指定为0,但是,当尝试绑定一个临时端口时,它被确定在临时端口范围内的所有端口号目前都被使用。
cal_port_range ip(7)。
EBADF sockfd is not a valid file descriptor.Sockfd不是一个有效的文件描述符。
EINVAL The socket is already bound to an address.
EINVAL addrlen is wrong, or addr is not a valid address for this socket's domain.
ENOTSOCK
The file descriptor sockfd does not refer to a socket.
The following errors are specific to UNIX domain (AF_UNIX) sockets:
EACCES Search permission is denied on a component of the path prefix. (See also path_resolution(7).)
EADDRNOTAVAIL
A nonexistent interface was requested or the requested address was not local.
EFAULT addr points outside the user's accessible address space.
ELOOP Too many symbolic links were encountered in resolving addr.
ENAMETOOLONG
addr is too long.
ENOENT A component in the directory prefix of the socket pathname does not exist.
ENOMEM Insufficient kernel memory was available.
ENOTDIR
A component of the path prefix is not a directory.
EROFS The socket inode would reside on a read-only filesystem.
CONFORMING TO
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD (bind() first appeared in 4.2BSD).
NOTES
POSIX.1 does not require the inclusion of <sys/types.h>, and this header file is not required on Linux. However, some historical (BSD) implementations
required this header file, and portable applications are probably wise to include it.
For background on the socklen_t type, see accept(2).
BUGS
The transparent proxy options are not described.
EXAMPLE
An example of the use of bind() with Internet domain sockets can be found in getaddrinfo(3).
The following example shows how to bind a stream socket in the UNIX (AF_UNIX) domain, and accept connections:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MY_SOCK_PATH "/somepath"
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
int sfd, cfd;
struct sockaddr_un my_addr, peer_addr;
socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
handle_error("socket");
memset(&my_addr, 0, sizeof(struct sockaddr_un));
/* Clear structure */
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH,
sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr,
sizeof(struct sockaddr_un)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
/* Now we can accept incoming connections one
at a time using accept(2) */
peer_addr_size = sizeof(struct sockaddr_un);
cfd = accept(sfd, (struct sockaddr *) &peer_addr,
&peer_addr_size);
if (cfd == -1)
handle_error("accept");
/* Code to deal with incoming connection(s)... */
/* When no longer required, the socket pathname, MY_SOCK_PATH
should be deleted using unlink(2) or remove(3) */
}
SEE ALSO
accept(2), connect(2), getsockname(2), listen(2), socket(2), getaddrinfo(3), getifaddrs(3), ip(7), ipv6(7), path_resolution(7), socket(7), unix(7)
COLOPHON
This page is part of release 5.05 of the Linux man-pages project. A description of the project, information about reporting bugs, and the latest version
of this page, can be found at https://www.kernel.org/doc/man-pages/.
Linux 2019-03-06
参考文档
[1] linux man手册
[2]《Linux高性能服务器》
[3]《Unix网络编程卷1》