linux1.2.13源码中,管理sock结构体的数据结构及操作函数

2024-03-27 21:48

本文主要是介绍linux1.2.13源码中,管理sock结构体的数据结构及操作函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

tcp和udp等协议在传输层都对应一个sock结构,该结构是实现协议的重要结构体,而传输层实现的就是对该结构体的管理。利用一个哈希链表根据端口号保存sock结构体。有了保存sock结构的数据结构后,还需要一系列的操作函数。代码如下。

/**	See if a socket number is in use.*/
// 看socket的端口是否在使用 
static int sk_inuse(struct proto *prot, int num)
{struct sock *sk;// 根据端口号取得哈希链表中的一个链表for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];sk != NULL;  sk=sk->next) {if (sk->num == num) return(1);}return(0);
}/**	Pick a new socket number*/
// 随机获取一个端口
unsigned short get_new_socknum(struct proto *prot, unsigned short base)
{static int start=0;/** Used to cycle through the port numbers so the* chances of a confused connection drop.*/int i, j;int best = 0;int size = 32767; /* a big num. */struct sock *sk;// 大于1024if (base == 0) base = PROT_SOCK+1+(start % 1024);if (base <= PROT_SOCK) {base += PROT_SOCK+(start % 1024);}/* Now look through the entire array and try to find an empty ptr. */for(i=0; i < SOCK_ARRAY_SIZE; i++) {j = 0;// 找到一条链表sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];// 找到链表中的最后一个节点while(sk != NULL) {sk = sk->next;j++;}// 该链表上还没有节点,说明这个端口还没有被使用过,返回该端口号,更新start变量if (j == 0) {start =(i+1+start )%1024;return(i+base+1);}/*j为本次循环的队列的节点数,best记录新端口所属队列的索引,size为本次循环为止节点数最少的队列的节点数,为了避免单个队列过长,找可用端口的时候,不仅要找到一个可用的端口,而且尽量保证端口所对应的队列不会过长,避免查找的时候比较慢,所以for循环是为了找出哈希链表中节点数最少的队列对应的索引。然后往该队列插入一个新的端口节点*/if (j < size) {best = i;size = j;}}/* Now make sure the one we want is not in use. */// 在一条队列中找到一个未使用的端口号,SOCK_ARRAY_SIZE保证哈希后对应的是同一个队列while(sk_inuse(prot, base +best+1)) {best += SOCK_ARRAY_SIZE;}return(best+base+1);
}/**	Add a socket into the socket tables by number.*/void put_sock(unsigned short num, struct sock *sk)
{struct sock *sk1;struct sock *sk2;int mask;unsigned long flags;sk->num = num;sk->next = NULL;num = num &(SOCK_ARRAY_SIZE -1);/* We can't have an interrupt re-enter here. */save_flags(flags);cli();// 使用的socket数sk->prot->inuse += 1;// 最多使用的socket数if (sk->prot->highestinuse < sk->prot->inuse)sk->prot->highestinuse = sk->prot->inuse;// 链表为空,sk成为第一个节点if (sk->prot->sock_array[num] == NULL) {sk->prot->sock_array[num] = sk;restore_flags(flags);return;}restore_flags(flags);// mask为0xff000000 => 0xffff0000 => 0xffffff00 => 0xfffffffffor(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) {if ((mask & sk->saddr) &&(mask & sk->saddr) != (mask & 0xffffffff)) {mask = mask << 8;break;}}cli();// 根据端口找到对应的链表,找到对应的位置插入队列sk1 = sk->prot->sock_array[num];for(sk2 = sk1; sk2 != NULL; sk2=sk2->next) {if (!(sk2->saddr & mask)) {if (sk2 == sk1) {sk->next = sk->prot->sock_array[num];sk->prot->sock_array[num] = sk;sti();return;}sk->next = sk2;sk1->next= sk;sti();return;}sk1 = sk2;}/* Goes at the end. */sk->next = NULL;sk1->next = sk;sti();
}/**	Remove a socket from the socket tables.*/static void remove_sock(struct sock *sk1)
{struct sock *sk2;unsigned long flags;if (!sk1->prot) {printk("sock.c: remove_sock: sk1->prot == NULL\n");return;}/* We can't have this changing out from under us. */save_flags(flags);cli();sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];// 是队列的第一个节点if (sk2 == sk1) {sk1->prot->inuse -= 1;sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;restore_flags(flags);return;}// 找sk1while(sk2 && sk2->next != sk1) {sk2 = sk2->next;}// 找到if (sk2) {sk1->prot->inuse -= 1;sk2->next = sk1->next;restore_flags(flags);return;}restore_flags(flags);
}/**	Destroy an AF_INET socket*/void destroy_sock(struct sock *sk)
{struct sk_buff *skb;sk->inuse = 1;			/* just to be safe. *//* In case it's sleeping somewhere. */if (!sk->dead) sk->write_space(sk);remove_sock(sk);/* Now we can no longer get new packets. */delete_timer(sk);/* Nor send them */del_timer(&sk->retransmit_timer);while ((skb = tcp_dequeue_partial(sk)) != NULL) {IS_SKB(skb);kfree_skb(skb, FREE_WRITE);}/* Cleanup up the write buffer. */while((skb = skb_dequeue(&sk->write_queue)) != NULL) {IS_SKB(skb);kfree_skb(skb, FREE_WRITE);}/**	Don't discard received data until the user side kills its*	half of the socket.*/if (sk->dead) {while((skb=skb_dequeue(&sk->receive_queue))!=NULL) {/** This will take care of closing sockets that were* listening and didn't accept everything.*/// 处理listen型的socket,监听套接字接收队列里的skb关联的sock结构是一个新建的而不是skif (skb->sk != NULL && skb->sk != sk) {IS_SKB(skb);skb->sk->dead = 1;// 关闭连接skb->sk->prot->close(skb->sk, 0);}IS_SKB(skb);kfree_skb(skb, FREE_READ);}}	/* Now we need to clean up the send head. */cli();// 清空为了重传而缓存的数据包for(skb = sk->send_head; skb != NULL; ){struct sk_buff *skb2;/** We need to remove skb from the transmit queue,* or maybe the arp queue.*/if (skb->next  && skb->prev) {
/*			printk("destroy_sock: unlinked skb\n");*/IS_SKB(skb);skb_unlink(skb);}skb->dev = NULL;// unlink后link3指针仍然指向下一个skb节点skb2 = skb->link3;kfree_skb(skb, FREE_WRITE);skb = skb2;}sk->send_head = NULL;sti();/* And now the backlog. */// 还没来得及移到receive_queue队列的而缓存在back_log队列的skbwhile((skb=skb_dequeue(&sk->back_log))!=NULL) {/* this should never happen. */
/*		printk("cleaning back_log\n");*/kfree_skb(skb, FREE_READ);}/* Now if it has a half accepted/ closed socket. */if (sk->pair) {sk->pair->dead = 1;sk->pair->prot->close(sk->pair, 0);sk->pair = NULL;}/** Now if everything is gone we can free the socket* structure, otherwise we need to keep it around until* everything is gone.*/if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) {kfree_s((void *)sk,sizeof(*sk));} else {/* this should never happen. *//* actually it can if an ack has just been sent. */sk->destroy = 1;sk->ack_backlog = 0;sk->inuse = 0;reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);}
}struct sock *get_sock(struct proto *prot, unsigned short num,unsigned long raddr,unsigned short rnum, unsigned long laddr)
{struct sock *s;struct sock *result = NULL;int badness = -1;unsigned short hnum;hnum = ntohs(num);/** SOCK_ARRAY_SIZE must be a power of two.  This will work better* than a prime unless 3 or more sockets end up using the same* array entry.  This should not be a problem because most* well known sockets don't overlap that much, and for* the other ones, we can just be careful about picking our* socket number when we choose an arbitrary one.*/for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];s != NULL; s = s->next) {int score = 0;if (s->num != hnum) continue;if(s->dead && (s->state == TCP_CLOSE))continue;/* local address matches? */if (s->saddr) {if (s->saddr != laddr)continue;score++;}/* remote address matches? */if (s->daddr) {if (s->daddr != raddr)continue;score++;}/* remote port matches? */if (s->dummy_th.dest) {if (s->dummy_th.dest != rnum)continue;score++;}/* perfect match? */// 全匹配,直接返回if (score == 3)return s;/* no, check if this is the best so far.. */if (score <= badness)continue;// 记录最好的匹配项result = s;badness = score;}return result;
}

协议每次新建一个socket的时候就会在底层生成一个sock结构体,然后插入大到哈希链表中,收到数据时候根据ip和端口从哈希链表中找到对应的sock结构体。

这篇关于linux1.2.13源码中,管理sock结构体的数据结构及操作函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853488

相关文章

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL