2.深入了解bind函数

1.查看方法

使用指令:man bind

bind

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_addrsin_port或者sin6_addrsin6_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》

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

紫荆鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值