如何深入理解TCP/IP协议的bind实现
发表于:2025-02-05 作者:千家信息网编辑
千家信息网最后更新 2025年02月05日,这篇文章给大家介绍如何深入理解TCP/IP协议的bind实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。按照socket网络编程的顺序,我们这一篇来分析bind函数。我们通过s
千家信息网最后更新 2025年02月05日如何深入理解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安全错误
数据库的锁怎样保障安全
盐城智能刀片服务器定制
无锡应用刀片服务器
基站和软件开发的区别和联系
vfp中从其他表添加数据库
福田区光纤网络技术开发商家
英国网络安全教育
细化和量化数据库
网络安全主题班级
网络安全证书怎么卸载
聚力汇通网络技术有限公司
银川创利大业网络技术
幻塔的第一个服务器是什么
方舟怎么让服务器炸掉
服务器的管理地址怎么查询
极品飞车9建立服务器错误
广州一九一八网络技术
怎么架设ftp服务器
南瑞服务器管理口地址
python 写数据到数据库
诗歌朗诵网络安全
服务器人员工资
wow提示没有可用服务器
网络技术三级与四级
山东大学生网络技术大赛
分层网络技术及其应用研究
在家里赚钱的网络技术
在线代理服务器代理服务器
ibm服务器 固态硬盘
app斗牛软件开发
全省网络安全会议