如何深入理解TCP/IP协议的bind实现
发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章给大家介绍如何深入理解TCP/IP协议的bind实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。按照socket网络编程的顺序,我们这一篇来分析bind函数。我们通过s
千家信息网最后更新 2026年11月03日如何深入理解TCP/IP协议的bind实现
这篇文章给大家介绍如何深入理解TCP/IP协议的bind实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
按照socket网络编程的顺序,我们这一篇来分析bind函数。我们通过socket函数拿到了一个socket结构体。bind函数的逻辑其实比较简单,他就是给socket结构体绑定一个地址,简单来说,就是给他的某些字段赋值。talk is cheap。show me the code。
static int sock_bind(int fd, struct sockaddr *umyaddr, int addrlen)
{
struct socket *sock;
int i;
char address[MAX_SOCK_ADDR];
int err;
// 通过文件描述符找到对应的socket
if (!(sock = sockfd_lookup(fd, NULL)))
return(-ENOTSOCK);
if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0)
return err;
if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0)
{
return(i);
}
return(0);
}
主要是两个函数,我们一个个来。
1 sockfd_lookup
通过之前一些文章的分析,我们应该数socket和文件的内存布局比较熟悉了。下面的代码不难理解。就是根据文件描述符从pcb中找到inode节点。因为inode节点里保存了socket结构体,所以最后返回fd对应的socke结构体就行。
// 通过fd找到file结构体,从而找到inode节点,最后找到socket结构体
static inline struct socket *sockfd_lookup(int fd, struct file **pfile)
{
struct file *file;
struct inode *inode;
if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd]))
return NULL;
inode = file->f_inode;
if (!inode || !inode->i_sock)
return NULL;
if (pfile)
*pfile = file;
return socki_lookup(inode);
}
// inode和socket互相引用
inline struct socket *socki_lookup(struct inode *inode)
{
return &inode->u.socket_i;
}
2 sock->ops->bind
我们回顾socket那篇文章可以知道socket结构体里保存了一些列的操作函数,假设是协议簇是ipv4,那么bind函数就是inet_bind函数(省略了部分代码)。
// 给socket绑定一个地址
static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
int addr_len)
{
struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;
// 拿到底层的sock结构体
struct sock *sk=(struct sock *)sock->data, *sk2;
unsigned short snum = 0 /* Stoopid compiler.. this IS ok */;
int chk_addr_ret;
// raw协议的这些数据由用户填充
if(sock->type != SOCK_RAW)
{ // 已经绑定了端口
if (sk->num != 0)
return(-EINVAL);
snum = ntohs(addr->sin_port);
// 端口无效则随机获取一个非root才能使用的端口
if (snum == 0)
{
snum = get_new_socknum(sk->prot, 0);
}
// 小于1024的端口需要超级用户权限
if (snum < PROT_SOCK && !suser())
return(-EACCES);
}
// 判断ip
chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
// 非法地址
if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST)
return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
// 记录ip
if (chk_addr_ret || addr->sin_addr.s_addr == 0)
sk->saddr = addr->sin_addr.s_addr;
if(sock->type != SOCK_RAW)
{
/* Make sure we are allowed to bind here. */
cli();
// 遍历哈希表,哈希表冲突解决法是链地址法,校验绑定的端口的合法性
for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];
sk2 != NULL; sk2 = sk2->next)
{
// 端口还没有绑定过,直接校验下一个
if (sk2->num != snum)
continue;
// 端口已经被使用,没有设置可重用标记,比如断开连接后在2msl内是否可以重用,通过setsockopt函数设置
if (!sk->reuse)
{
sti();
return(-EADDRINUSE);
}
// 端口一样,但是ip不一样,ok,下一个
if (sk2->saddr != sk->saddr)
continue; /* socket per slot ! -FB */
// 端口和ip都一样。被监听的端口不能同时被使用
if (!sk2->reuse || sk2->state==TCP_LISTEN)
{
sti();
return(-EADDRINUSE);
}
}
sti();
// 保证该sk不在sock_array队列里
remove_sock(sk);
// 挂载到sock_array里
put_sock(snum, sk);
// tcp头中的源端口
sk->dummy_th.source = ntohs(sk->num);
sk->daddr = 0;
sk->dummy_th.dest = 0;
}
return(0);
}
bind函数主要是对待绑定的ip和端口做一个校验,合法的时就记录在sock结构体中。并且把sock结构体挂载到一个全局的哈希表里。
关于如何深入理解TCP/IP协议的bind实现就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
端口
结构
函数
地址
就是
文件
节点
哈希
合法
代码
内容
文章
更多
用户
篇文章
分析
帮助
不错
两个
全局
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
咖啡网
上海喔噻互联网科技有限公司
互联网科技公司简介
广州淘业互联网络科技
互联网科技公司起名
互联网科技行业发展
科技互联网公司装修
中资互联网科技
科技服务与互联网
赫美联合互联网科技
广州紫鲸互联网科技
美国互联网前沿科技
互联网科技公司的市场部门
深圳前海聚择互联网科技有限公司
创业天下互联网科技有限公司
西安小鹰速贷互联网科技有限公司
国大互联网教育科技有限公司薪资
合肥互联网科技公司公章图片
沐思想互联网科技有限公司
银川新华互联网科技学校原画
科技互联网政务服务
腾讯阿里互联网科技
卓越科技互联网 招聘
互联网科技公司需要的职位
科技互联网的估值
智腾互联网科技有限公司
亳州好赞互联网科技有限公司
互联网保险科技创业
华夏恒生互联网科技013171
新氧科技和美国互联网有关系吗