在socket创建成功之后,调用bind函数以完成对指定地址和端口的绑定工作;

下面详细分析bind相关代码;

 /*
* Bind a name to a socket. Nothing much to do here since it's
* the protocol's responsibility to handle the local address.
*
* We move the socket address to kernel space before we call
* the protocol layer (having also checked the address is ok).
*/ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{
struct socket *sock;
struct sockaddr_storage address;
int err, fput_needed; /* 获取socket ,fput_need标识是否需要减少文件引用计数*/
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock) {
/* 将用户空间地址复制到内核空间 */
err = move_addr_to_kernel(umyaddr, addrlen, &address);
if (err >= ) {
/* 安全模块的bind检查 */
err = security_socket_bind(sock,
(struct sockaddr *)&address,
addrlen);
if (!err)
/* 调用socket的bind操作 */
err = sock->ops->bind(sock,
(struct sockaddr *)
&address, addrlen);
} /* 根据fput_needed决定是否减少引用计数 */
fput_light(sock->file, fput_needed);
}
return err;
}

首先根据传入的socket描述符来获取socket结构;

 static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
/* 获取fd结构 */
struct fd f = fdget(fd);
struct socket *sock; *err = -EBADF;
if (f.file) {
/* 从文件的私有数据中获取socket */
sock = sock_from_file(f.file, err);
if (likely(sock)) {
/* 设置是否需要减少引用计数的标志 */
*fput_needed = f.flags;
return sock;
}
fdput(f);
}
return NULL;
}

之后,将用户空间的地址拷贝到内核空间;

 /*
* Support routines.
* Move socket addresses back and forth across the kernel/user
* divide and look after the messy bits.
*/ /**
* move_addr_to_kernel - copy a socket address into kernel space
* @uaddr: Address in user space
* @kaddr: Address in kernel space
* @ulen: Length in user space
*
* The address is copied into kernel space. If the provided address is
* too long an error code of -EINVAL is returned. If the copy gives
* invalid addresses -EFAULT is returned. On a success 0 is returned.
*/ /* 复制socket地址到内核空间 */
int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr)
{
/* 长度检查 */
if (ulen < || ulen > sizeof(struct sockaddr_storage))
return -EINVAL;
if (ulen == )
return ; /* 从用户空间拷贝数据 */
if (copy_from_user(kaddr, uaddr, ulen))
return -EFAULT; /* 审计信息 */
return audit_sockaddr(ulen, kaddr);
}

最后,来看最核心的函数,sock->ops->bind调用inet_bind(为什么? 具体可以参考本博套接字调用关系那片文章),inet_bind将会进行一些列检查之后,调用传输层的sk->sk_prot->get_port函数来执行更详细的绑定工作,比如tcp会调用inet_csk_get_port函数;

/* 地址绑定 */
int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
struct sock *sk = sock->sk;
struct inet_sock *inet = inet_sk(sk);
struct net *net = sock_net(sk);
unsigned short snum;
int chk_addr_ret;
u32 tb_id = RT_TABLE_LOCAL;
int err; /* If the socket has its own bind function then use it. (RAW) */
/*
如果传输控制块有自己的bind操作则调用,
目前只有raw实现了自己的bind
*/
if (sk->sk_prot->bind) {
err = sk->sk_prot->bind(sk, uaddr, addr_len);
goto out;
} err = -EINVAL;
/* 地址长度错误 */
if (addr_len < sizeof(struct sockaddr_in))
goto out; /* 如果不是AF_INET协议族 */
if (addr->sin_family != AF_INET) {
/* Compatibility games : accept AF_UNSPEC (mapped to AF_INET)
* only if s_addr is INADDR_ANY.
*/
err = -EAFNOSUPPORT; /* 接受AF_UNSPEC && s_addr=htonl(INADDR_ANY)的情况 */
if (addr->sin_family != AF_UNSPEC ||
addr->sin_addr.s_addr != htonl(INADDR_ANY))
goto out;
} tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id;
chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id); /* Not specified by any standard per-se, however it breaks too
* many applications when removed. It is unfortunate since
* allowing applications to make a non-local bind solves
* several problems with systems using dynamic addressing.
* (ie. your servers still start up even if your ISDN link
* is temporarily down)
*/
err = -EADDRNOTAVAIL; /* 合法性检查 */
if (!net->ipv4.sysctl_ip_nonlocal_bind &&
!(inet->freebind || inet->transparent) &&
addr->sin_addr.s_addr != htonl(INADDR_ANY) &&
chk_addr_ret != RTN_LOCAL &&
chk_addr_ret != RTN_MULTICAST &&
chk_addr_ret != RTN_BROADCAST)
goto out; /* 源端口 */
snum = ntohs(addr->sin_port);
err = -EACCES; /* 绑定特权端口的权限检查 */
if (snum && snum < inet_prot_sock(net) &&
!ns_capable(net->user_ns, CAP_NET_BIND_SERVICE))
goto out; /* We keep a pair of addresses. rcv_saddr is the one
* used by hash lookups, and saddr is used for transmit.
*
* In the BSD API these are the same except where it
* would be illegal to use them (multicast/broadcast) in
* which case the sending device address is used.
*/
lock_sock(sk); /* Check these errors (active socket, double bind). */
err = -EINVAL; /* 传输控制块的状态不是CLOSE || 存在本地端口 */
if (sk->sk_state != TCP_CLOSE || inet->inet_num)
goto out_release_sock; /* 设置源地址rcv_addr用作hash查找,saddr用作传输 */
inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; /* 组播或者广播,使用设备地址 */
if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
inet->inet_saddr = ; /* Use device */ /* Make sure we are allowed to bind here. */ /*
端口不为0,或者端口为0允许绑定
则使用协议的具体获取端口函数绑定端口
*/
if ((snum || !inet->bind_address_no_port) &&
sk->sk_prot->get_port(sk, snum)) { /* 绑定失败 */
inet->inet_saddr = inet->inet_rcv_saddr = ; /* 端口在使用中 */
err = -EADDRINUSE;
goto out_release_sock;
} /* 传输控制块已经绑定本地地址或端口标志 */
if (inet->inet_rcv_saddr)
sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK; /* 设置源端口 */
inet->inet_sport = htons(inet->inet_num); /* 设置目的地址和端口默认值 */
inet->inet_daddr = ;
inet->inet_dport = ; /* 设置路由默认值 */
sk_dst_reset(sk);
err = ;
out_release_sock:
release_sock(sk);
out:
return err;
}
EXPORT_SYMBOL(inet_bind);

TCP bind()系统调用实现部分,请阅读<TCP层bind系统调用的实现分析>

bind系统调用的更多相关文章

  1. Socket bind系统调用简要分析

    主要查看linux kernel 源码:Socket.c 以及af_inet.c文件 1.1 bind分析 #include <sys/types.h> /* See NOTES */#i ...

  2. TCP层bind系统调用的实现分析

    说明:该文章中部分代码未能完全理解透彻,可能对您造成误解,请慎读: 并建议您先阅读本博另外一篇文章:<Linux TCP套接字选项 之 SO_REUSEADDR && SO_RE ...

  3. Linux进程间通信(八):流套接字 socket()、bind()、listen()、accept()、connect()、read()、write()、close()

    前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编 ...

  4. Linux进程间通信(九):数据报套接字 socket()、bind()、sendto()、recvfrom()、close()

    前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接字的使用. 一.简单回顾——什么是数据报套 ...

  5. socket相关系统调用的调用流程

    最近一直在读内核网络协议栈源码,这里以ipv4/tcp为例对socket相关系统调用的流程做一个简要整理,这些相关系统调用的内部细节虽然各有不同,但其调用流程则基本一致: 调用流程: (1)系统调用 ...

  6. listen系统调用

    /* * Perform a listen. Basically, we allow the protocol to do anything * necessary for a listen, and ...

  7. Linux运维实战之DNS(bind)服务器的安装与配置

    转自http://sweetpotato.blog.51cto.com/533893/1598225 上次博文我们讨论了DNS的基础,本次博文我们重点来看看如何配置一台DNS服务器. [本次博文的主要 ...

  8. xenomai内核解析之双核系统调用(一)

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 xenomai 内核系统调用 一.32位Lin ...

  9. 从Linux源码看Socket(TCP)的bind

    从Linux源码看Socket(TCP)的bind 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就来从Linux源码的角度看下Server ...

随机推荐

  1. PGM学习之六 从有向无环图(DAG)到贝叶斯网络(Bayesian Networks)

    本文的目的是记录一些在学习贝叶斯网络(Bayesian Networks)过程中遇到的基本问题.主要包括有向无环图(DAG),I-Maps,分解(Factorization),有向分割(d-Separ ...

  2. BZOJ5118 Fib数列2(矩阵快速幂)

    特殊矩阵的幂同样满足费马小定理. #include<iostream> #include<cstdio> #include<cmath> #include<c ...

  3. java的4种引用 强软弱虚

    &amp;lt;img src="https://pic4.zhimg.com/d643d9ab5c933ac475cfa23063bed137_b.png" data-r ...

  4. (待修莫队 没过! 抽空在检查)Dynamic len(set(a[L:R])) UVA - 12345

    #include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...

  5. es各类SearchType的意思

    元素 含义 QUERY_THEN_FETCH 查询是针对所有的块执行的,但返回的是足够的信息,而不是文档内容(Document).结果会被排序和分级,基于此,只有相关的块的文档对象会被返回.由于被取到 ...

  6. FFT常数优化(共轭优化)

    最近闲着无聊研究了下\(FFT\)的常数优化,大概就是各种\(3\)次变\(2or1.5\)次之类的,不过没见过啥题卡这个的吧. 关于\(FFT\)可以看这里:浅谈FFT&NTT. 关于复数 ...

  7. PHP 字符串数组按照拼音排序的问题

    拼音排序的规则: 字符串包括特殊字符.数字.英文字符.中文字符等等,排序结果要求,特殊字符排在第一梯队,将其按照首个字符ascii码表进行排序,数字字符排在第二梯队,将首个字符数字按照数字大小排序,英 ...

  8. 谷歌钦定的编程语言Kotlin大揭秘

    第一时间关注程序猿(媛)身边的故事 谷歌钦定的编程语言Kotlin大揭秘 语法+高级特性+实现原理:移动开发者升职加薪宝典! 谷歌作为世界级的科技公司巨头,强悍的技术研发与创新能力使其一直是业界的楷模 ...

  9. 用Python实现的数据结构与算法:链表

    一.概述 链表(linked list)是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接(参考 <算法:C语言实现>). 根据结构的不同,链表可以 ...

  10. scala 的安装 与 IDEA安装使用

    一.安装 scala 1.下载scala-2.11.8.msi 安装包,   首先去官网http://www.scala-lang.org/,然后点击导航栏的DOWNLOAD,进入下载链接:http: ...