OSPF链路状态(LS)路由算法(C/C++代码实现)

路由算法是一种用于确定节点中数据包路由的方法。对于网络的每个节点,该算法确定一个路由表,在每个目的地,该路由表与输出线路相匹配。该算法应该导致一致的路由,也就是说没有循环。这意味着您不应该将数据包从一个节点路由到另一个可以发回数据包的节点。

定义:通过跟随数据包到达目的地来建立路由的过程。它是一组循序渐进的过程,用于有效地引导互联网的流量。一旦一个数据包从源离开,那么几个路径就可以提供给它的目的地。这种算法主要从数学上确定最佳车道。

有不同的方法用于不同的路由算法来决定最佳车道。例如,距离向量算法分析通过每个节点的所有可访问路线的图,以确定每个即时邻居的旅行费用。可以为每个节点收集该数据以生成距离表,从而确定任意两个节点之间的最佳车道。在这种方法中,可以创建路由表来输入数据包所遵循的路由的信息。

OSPF链路状态(LS)路由算法(C/C++代码实现)_第1张图片

在OSI模型(开放系统互连)中,路由可以存在于网络层之上。这是OSI模型中的第三层。因此,它确定了网络上从源到目的地传输数据包的最佳通道。

路由算法有哪些类型

路由算法主要有三种类型:

距离矢量(距离矢量路由);
到链路状态(链路状态路由);
路径到矢量(路径-矢量路由)。

距离矢量路由算法

距离矢量路由算法要求每个节点在邻居之间,也就是直接连接的节点之间交换信息。因此,每个节点可以通过添加关于其所有邻居的信息来保持表的更新。此表显示了每个节点和要到达的每个网络的距离。首先在Arpanet中实现的是,当节点数量增加时,这项技术很快就会变得麻烦,因为我们必须在节点之间携带大量信息。RIP(路由信息协议)是使用距离矢量的协议的最佳示例。

在这种类型的算法中,每个路由器向其邻居广播一个向量,该向量列出了它可以到达的每个网络的相关度量,也就是跳数。因此,每个路由器都可以用从其邻居那里接收到的信息来构建路由表,但不知道​​所选路由上的路由器的标识。因此,这种解决方案的使用给外部路由协议带来了许多问题。事实上,假设所有路由器都使用相同的度量,而自治系统之间的情况可能并非如此。此外,一个自治系统可能有特殊的理由表现得与另一个自治体系不同。特别是,如果自治系统需要确定自治系统将如何传递其消息,例如出于安全原因,他不知道。

链路状态算法

链路状态算法最初旨在克服距离矢量路由的缺点。初始化路由器时,它必须定义连接到另一个节点的每个链路的成本。然后,节点将信息广播给自治系统中的所有节点,因此不仅广播给其邻居。根据所有这些信息,节点可以执行它们的计算以获得指示实现每个目的地的成本的路由表。当路由器接收到更改其路由表的信息时,它会通知其配置中的所有介入路由器。由于每个节点都有网络拓扑结构和每个链路的成本,因此可以将路由视为每个节点的中心。OSPF(Open Shortest Path First)实现了这一技术,它是第二代互联网协议。

链路状态算法解决了上述外部路由问题,但也提出了其他问题。各种自治系统可能具有不同的度量和特定的限制,因此不可能实现一致的路线。所有自治系统所需的所有信息的传播也可能很快变得难以管理。

路径向量算法

路径向量算法的目的是通过提供度量并寻求知道任何节点和必须跨越的自治系统可以到达哪个网络来克服前两类算法的缺点。这种方法与距离向量非常不同,因为路径向量没有考虑距离或成本。此外,事实上,每个列表路由信息都是必须遍历才能到达目的地路由器的自主系统,路径向量方法更倾向于外部路由系统。BGP(边界网关协议)属于这一类。

OSPF (Open Shortest Path First)

开放式最短路径优先(OSPF)是一种为IP网络开发的链路状态路由协议,基于最短路径第一(SPF)算法。OSPF是一种内部网关协议(IGP)。

在OSPF网络中,同一区域内的路由器或系统维护一个描述该区域拓扑结构的相同链路状态数据库。该区域中的每个路由器或系统根据其从同一区域中的所有其他路由器或系统接收的链路状态通告(LSA)以及其自身生成的LSA来生成其链路状态数据库。LSA是包含关于邻居和路径成本的信息的数据包。基于链路状态数据库,每个路由器或系统使用SPF算法计算一个以自身为根的最短路径生成树。

OSPF是第二代路由协议的一部分。它比RIP复杂得多,但性能更高,它使用了一个跟踪链路状态的分布式数据库。这些信息形成了网络拓扑和节点状态的描述,通过计算最短路径来定义路由算法。

该算法允许OSPF从一个节点计算最短路径,并在与每个链路相关的内容中指定约束。OSPF路由器通过位于IP之上的OSPF协议相互通信。现在看一下这个协议的细节。

链路状态协议的假设是,每个节点都可以检测与其邻居的链路状态(打开或关闭)以及该链路的成本。我们必须给每个节点足够的信息,使他能够找到到达任何目的地的最便宜的路线。每个节点都必须了解其邻居。如果每个节点都知道其他节点,就可以建立一个完整的网络地图。基于邻居状态的算法需要两种机制:传播关于链路状态的可靠信息,以及通过对链路状态的累积知识求和来计算路线。

一种解决方案是提供可靠的信息洪流,以确保每个节点从所有其他节点接收其信息副本。事实上,每个节点都会淹没其邻居,而邻居又会淹没自己的邻居。具体而言,每个节点创建自己的更新包,称为LSP(链路状态包),包含以下信息:

创建LSP的节点的标识。
具有相关链路成本的相邻节点列表。
序列号。
此消息的计时器(生存时间)。

路线计算是在接收到关于链路的所有信息之后执行的。根据完整的网络地图和链路成本,可以计算出最佳路线。在最短路径上使用Dijkstra算法进行计算。

在缩写OSPF(Open Shortest Path First)Open中,该词表示该算法是开放的,并得到IETF的支持。使用上述机制,OSPF协议添加了以下附加属性:

  • 路由消息的身份验证。故障可能导致灾难。例如,在有意或无意地接收到错误消息后,或者在前锋消息修改其路由表后,计算出一个路由表的节点自动接收所有网络数据包,在该路由表中,所有节点都可以以零成本实现。可以通过验证颁发者的消息来避免这些问题。早期版本的OSPF身份验证密码为8字节。最新版本具有更强的身份验证功能。

  • 新的层次结构。这种层次结构允许更好的可伸缩性。OSPF通过将区域划分为时代(区域)引入了另一个层次结构。这意味着域内的路由器不需要知道如何到达现场的所有网络。只是他知道如何达到合适的年龄。这导致要传输和存储的信息的减少。

OSPF消息有几种类型,但它们都使用相同的头,如图所示。

OSPF链路状态(LS)路由算法(C/C++代码实现)_第2张图片

OSPF链路状态(LS)路由算法(C/C++代码实现)_第3张图片
当前版本为2。用值定义了五种类型​​从1到5。源地址表示邮件的发件人。时代的标识指示发送节点所在的时代。如果没有身份验证,则身份验证类型的值为0,如果身份验证密码为1,如果在以下4个字节中实现和描述了身份验证技术,则为2。

这五种类型的消息将Hello消息作为Type 1。

OSPF链路状态(LS)路由算法(C/C++代码实现)_第4张图片

此消息由节点发送给其邻居,以告诉他们它始终存在且未损坏。其他四种类型用于发送查询、发货或无罪释放LSP消息等信息。这些消息主要携带链路状态通告(LSA),即链路状态信息。一条消息可以包含多个OSPF LSA。

该图显示了一种携带消息1的OSPF LSA类型。
OSPF链路状态(LS)路由算法(C/C++代码实现)_第5张图片

OSPF链路状态(LS)路由算法(C/C++代码实现)_第6张图片
OSPF链路状态(LS)路由算法(C/C++代码实现)

为给定的一组节点(路由器)实现OSPF链路状态(LS)路由算法。节点由小写字母(a-z)表示。然后,当给定源节点时,项目输出每个节点的最短路径成本和路径。因此,程序将询问网络中路由器的数量、代表第一个节点的字母和源节点的字母。除了第一个节点之外的节点用字母表中的连续字母表示。例如,如果有5个路由器,并且第一个节点是d,那么第二、第三、第四和第五个路由器将分别使用字母e、f、g和h来表示。该程序还将要求一个成本矩阵,其中包含节点之间每个链路的成本。每个链接的成本都是一个大于1的正值。如果成本矩阵中存在0,则意味着同一节点到达该节点的成本为零。如果成本矩阵中有-1,则意味着两个节点之间没有直接路径。LS算法利用Dijkstra算法来寻找节点之间的最短路径。它还维护了一个简单的路由表来存储这些信息。下面给出了一个成本矩阵示例。

...
int main(int argc, char *argv[])
{
...

//Displaying cost matrix

    Display_Cost_Matrix(cost_matrix, number_of_routers, first_node_character); //Calling Display_Cost_Matrix() function to display the cost matrix

//Displaying cost matrix
...
//Initializing for Dijkstra algorithm

    starting_node = source_node - first_node_character + 1; ///Determining the starting node for the algorithm

    for(i = 1; i <= number_of_routers; i++) //Initializig flags for all nodes
        if(i == starting_node)
            node_flag[i] = 1;
        else
            node_flag[i] = 0;

    for(i = 0; i <= number_of_routers; i++) //Initializing link state table
    {
        for(j = 1; j <= number_of_routers; j++)
            link_state_table[i][j] = -1;
    }

//Initializing for Dijkstra algorithm
...
//Dijkstra algorithm starting...
...
    while(1)
    {
        for(j = 1; j <= number_of_routers; j++) 
        {
            if(!node_flag[j]) 
            {
                if(cost_matrix[previous_node][j] != -1) 
                {
                    if(link_state_table[i-1][j] > 0 && link_state_table[i-1][j] < cost_matrix[previous_node][j] + previous_cost) 
                    {
                        link_state_table[i][j] = link_state_table[i-1][j]; 
                        tracker[i][j].node_from = tracker[i-1][j].node_from; 
                        tracker[i][j].i_from = i - 1; 
                        tracker[i][j].j_from = j; 
                    }
                    else
                    {
                        link_state_table[i][j] = cost_matrix[previous_node][j] + previous_cost; 
                        tracker[i][j].node_from = first_node_character + previous_node - 1; 
                        tracker[i][j].i_from = i - 1; 
                        tracker[i][j].j_from = previous_node; 
                    }
                }
                else if(link_state_table[i-1][j] > 0) 
                {
                    link_state_table[i][j] = link_state_table[i-1][j]; 
                    tracker[i][j].node_from = tracker[i-1][j].node_from; 
                    tracker[i][j].i_from = i - 1; 
                    tracker[i][j].j_from = j; 
                }
            }
        }
...
        for(j = 1; j <= number_of_routers; j++) 
        {
            if(link_state_table[i][j] != -1)
            {
                previous_cost = link_state_table[i][j];
                previous_node = j;
                break;
            }
        }
        for(j = 1; j <= number_of_routers; j++) ///Finding out minimum cost and node number for current node
        {
            if(link_state_table[i][j] != -1)
            {
                if(link_state_table[i][j] <= previous_cost)
                {
                    previous_cost = link_state_table[i][j];
                    previous_node = j;
                }
            }
        }
        node_flag[previous_node] = 1; 
        i++;
    }

    step_number = i; 

    for(i = 1; i <= number_of_routers; i++) each iteration
    {
        path_cost[i] = 0; 
        k = 0;
        if(i != starting_node) 
        {
            path_taken[i][k] = first_node_character + i - 1; 
            k++;
            for(j = 1; j <= step_number; j++) 
            {
                if(!path_cost[i] && link_state_table[j][i] != -1) 
                {
                    path_cost[i] = link_state_table[j][i]; 
                    current_i = j;
                    current_j = i; 
                    path_taken[i][k] = tracker[current_i][current_j].node_from; 
                }
                else if(path_cost[i] && link_state_table[j][i] != -1 && link_state_table[j][i] < path_cost[i]) 
                {
                    path_cost[i] = link_state_table[j][i];  cost
                    current_i = j; 
                    current_j = i; 
                    path_taken[i][k] = tracker[current_i][current_j].node_from; 
                }
            }
            k++;
            while(current_i && current_j) 
            {
                if(path_taken[i][k-1] != tracker[current_i][current_j].node_from) 
                {
                    path_taken[i][k] = tracker[current_i][current_j].node_from; 
                    k++;
                }
                temp_i = current_i;
                temp_j = current_j;
                current_i = tracker[temp_i][temp_j].i_from; 
                current_j = tracker[temp_i][temp_j].j_from;
            }
        }
        else 
        {
            path_taken[i][k] = source_node; 
            k++;
        }
        path_taken[i][k] = '\0';
    }

///Dijkstra algorithm ending...
...
    return 0;
}

运行结果:
OSPF链路状态(LS)路由算法(C/C++代码实现)_第7张图片

OSPF链路状态(LS)路由算法(C/C++代码实现)_第8张图片
If you need the complete source code, please add the WeChat number (c17865354792)

实现了给定的一组节点(路由器)实现OSPF链路状态(LS)路由算法。

总结

路由算法主要用于提高网络质量。通过使用该算法,可以确定适合网络的最佳路由。该算法适用于特定的协议。可以使用不同的算法方法来计算路线。根据网络类型及其应用,可以应用每种算法。该算法具有许多特性,如稳定性、正确性、效率、简单性、公平性和鲁棒性。

路由算法在连接不同系统以通过网络进行通信方面发挥着重要作用。路由器的主要职责是识别每个设备、其结构、存在和传输数据包。通过使用这些算法,可以在几秒钟内通过网络传输数据,可以安全地传输数据,并可以保持数据的质量。

Welcome to follow WeChat official account【程序猿编码

参考:RFC 2328 、RFC6549、RFC5709

你可能感兴趣的:(C/C++,算法,c语言,c++,路由算法,OSPF,Dijkstra算法)