设备发现协议

  网络环境下设备发现是一种比较常见的应用,比如查找打印机与WiFi。那么我们应该如何通过编程实现对网络中的特定设备进行查找呢?

  常用的方式有:IP广播与多播,以及基于这两种方式所实现的第三方协议,较著名的有Onvif协议。

1局域网广播

1.1 定义

  广播是一种一对所有的通信模式。有线电视网就是典型的广播型网络,我们的电视机实际上是接受到所有频道的信号,但只将一个频道的信号还原成画面。

  广播不用进行网络路径选择,不能穿越路由器。这是为了防止广播数据影响大面积的主机,引起广播灾难。

1.2 优缺点

1.2.1 优点

  • 网络设备简单,维护简单,布网成本低廉。
  • 由于服务器不用向每个客户机单独发送数据,所以服务器流量负载极低。

1.2.2 缺点

  • 无法针对每个客户的要求和时间及时提供个性化服务。
  • 网络允许服务器提供数据的带宽有限,客户端的最大带宽=服务总带宽。例如有线电视的客户端的线路支持100个频道(如果采用数字压缩技术,理论上可以提供 500个频道),即使服务商有更大的财力配置更多的发送设备、改成光纤主干,也无法超过此极限。
  • 不能在广域网上传播,这是为了防止广播风暴。

1.3 广播地址

  每一个网段都有一个广播地址,其格式为 xxx.xxx.xxx.255 的形式。计算方式如下:

                    网络地址 = IP地址 & 子网掩码

                    广播地址 = 网络地址 | (~子网掩码)

  代码:

/*
 * 通过ip地址与子网掩码计算广播地址
 * 算法流程:1. ip地址与子网掩码获得网络地址;
 *         2. 网络地址主机位全置1后得到广播地址 * @param[out] bc_addr 广播地址
 * @param[in] ip 主机IPv4地址
 * @param[in] mask 子网掩码
 * @param[in] len IPv4地址长度(16)
 * @return 返回广播地址
 */
char* cal_bc_addr(char* bc_addr, const char* ip, const char* mask)
{
    uint8_t bc[4] = {0};
    int ret = 0;

    printf("ip: %s\n", ip);
    printf("mask: %s\n", mask);

    ip[3] = ‘\0‘;
    ip[7] = ‘\0‘;
    ip[11] = ‘\0‘;

    mask[3] = ‘\0‘;
    mask[7] = ‘\0‘;
    mask[11] = ‘\0‘;

    bc[0] = (uint8_t)(atoi(ip) & atoi(mask)) | ~(uint8_t)atoi(mask);
    bc[1] = (uint8_t)(atoi(ip + 4) & atoi(mask + 4)) | ~(uint8_t)atoi(mask + 4);
    bc[2] = (uint8_t)(atoi(ip + 8) & atoi(mask + 8)) | ~(uint8_t)atoi(mask + 8);
    bc[3] = (uint8_t)(atoi(ip + 12) & atoi(mask + 12)) | ~(uint8_t)atoi(mask + 12);

    ret = sprintf(bc_addr, "%d.%d.%d.%d", bc[0], bc[1], bc[2], bc[3]);

    bc_addr[ret] = ‘\0‘;
    return bc_addr;
}
/**
 * 通过socket获取广播地址(仅限Linux)
 * @param[out] bc_addr 广播地址
 * @param[in] ifname 网口,如:"eth0"
 * @return 返回广播地址
 */
char* get_bc_addr(char* bc_addr, const char* ifname)
{
  int sock = socket(AF_INET,SOCK_DGRAM,0);
  if(sock < 0){
    perror("sock init error");
    goto on_return;
  }
  struct ifreq ifr;
  strncpy(ifr.ifr_name, ifname, strlen(ifname));
  if(ioctl(sock, SIOCGIFBRDADDR, &ifr) == -1){ // 获取广播地址
      perror("ioctl error");
      goto on_return;
  }
  memcpy(&bc_addr, (char *)&ifr->ifr_broadaddr, sizeof(struct sockaddr_in));
on_return:  if(sock > 0) close(sock);
  return bc_addr;
}

1.4 socket编程

1.4.1 IP选项

  广播是基于UDP的,使用时需要设置其IP选项进行设置,详见下表:

socket编程广播选项设置
setsockopt()选项 含义
SO_BROADCAST
广播

1.4.2 socket多播程序设计流程

  • 创建UDP套接字;
  • 获取广播地址,设置其端口号;
  • 设置IP选项:SO_BROADCAST;
  • 接收/发送广播消息。

1.4.3 代码

服务端:

#include<iostream>
#include<stdio.h>
#include<sys/socket.h>
#include<unistd.h>
#include<sys/types.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
using namespace std;
int main()
{
    setvbuf(stdout,NULL,_IONBF,0);
    fflush(stdout);
    int sock=-1;
    if((sock=socket(AF_INET,SOCK_DGRAM,0))==-1)
    {
        cout<<"sock error"<<endl;
        return -1;
    }
    const int opt=-1;
    int nb=0;
    nb=setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char*)&opt,sizeof(opt));//设置套接字类型
    if(nb==-1)
    {
        cout<<"set socket error...\n"<<endl;
        return -1;
    }
    struct sockaddr_in addrto;
    bzero(&addrto,sizeof(struct sockaddr_in));
    addrto.sin_family=AF_INET;
    addrto.sin_addr.s_addr=htonl(INADDR_BROADCAST);//套接字地址为广播地址
    addrto.sin_port=htons(6000);//套接字广播端口号为6000
    int nlen=sizeof(addrto);
    while(1)
    {
        sleep(1);
        char msg[]={"the message broadcast"};
        int ret=sendto(sock,msg,strlen(msg),0,(sockaddr*)&addrto,nlen);//向广播地址发布消息
        if(ret<0)
        {
            cout<<"send error...\n"<<endl;
            return -1;
        }
        else
        {
            printf("ok\n");
        }
    }
    return 0;
}

客户端:

#include<iostream>
#include<stdio.h>
#include<sys/socket.h>
#include<unistd.h>
#include<sys/types.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

using namespace std;
int main()
{
  setvbuf(stdout,NULL,_IONBF,0);
  fflush(stdout);
  struct sockaddr_in addrto;
  bzero(&addrto,sizeof(struct sockaddr_in));
  addrto.sin_family=AF_INET;
  addrto.sin_addr.s_addr=htonl(INADDR_ANY);
  addrto.sin_port=htons(6000);
  socklen_t len=sizeof(addrto);
  int sock=-1;
  if((sock=socket(AF_INET,SOCK_DGRAM,0))==-1){
    cout<<"socket error..."<<endl;
    return -1;
  }
  const int opt=-1;
  int nb=0;
  nb=setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char*)&opt,sizeof(opt));
  if(nb==-1){
    cout<<"set socket errror..."<<endl;
    return -1;
  }
  if(bind(sock,(struct sockaddr*)&(addrto),len)==-1){
    cout<<"bind error..."<<endl;
    return -1;
  }
  char msg[100]={0};
  while(1)
  {
    int ret=recvfrom(sock,msg,100,0,(struct sockaddr*)&addrto,&len);
    if(ret<=0){
      cout<<"read error..."<<endl;
    }else{
      printf("%s\t",msg);
    }
    sleep(1);
  }
  return 0;
}

2 多播

2.1 定义

  多播又称为组播,是一种一对多的通信方式。多播能使一个或多个多播源只把数据包发送给特定的多播组,而只有加入该多播组的主机才能接收到数据包。它是节省网络带宽的有效方法之一。在网络音频/视频广播的应用中,当需要将一个节点的信号传送到多个节点时,无论是采用重复点对点通信方式,还是采用广播方式,都会严重浪费网络带宽,只有多播才是最好的选择。

  多播可在广域网传播。由于多播是以组的形式参与的,因此不必担心未加入多播组的主机接收到消息,这一特性使它允许在广域网上传播。

2.2 多播地址

  在IPv4中,多播地址是一个D类IP地址,其范围从224.0.0.0~239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限(受限)多播地址三类:

  局部多播(224.0.0.0~224.0.0.255):这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包。

  预留多播(224.0.1.0~238.255.255.255):可用于全球范围(如Internet)或网络协议。

  受限多播(239.0.0.0~239.255.255.255):可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。

2.3 socket编程

2.3.1 IP选项设置

  多播的程序设计使用setsockopt()函数和getsockopt()函数来实现,组播的选项是IP层的,其选项值和含义见下表:

socket编程多播IP选项设置
setsockopt()/getsockopt()选项 含义
IP_MULTICAST_TTL 设置多播组跨网段数
IP_ADD_MEMBERSHIP 加入多播组
IP_DROP_MEMBERSHIP 离开多播组
IP_MULTICAST_IF 获取默认或设置接口
IP_MULTICAST_LOOP 设置数据回传

2.3.2 socket多播程序设计流程

  • 创建UPD套接字;
  • 设置IP选项:TTL、MEMBERSHIP、IF、LOOP;
  • 加入多播组;
  • 发送/接收数据;
  • 离开多播组。

2.3.3 代码

服务端:

#include<iostream>
#include<stdio.h>
#include<sys/socket.h>
#include<netdb.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#define MCAST_PORT 8888
#define MCAST_ADDR "224.0.0.88"  // 多播地址
#define MCAST_DATA "BROADCAST TEST DATA"  // 多播内容
#define MCAST_INTERVAL 5  //多播时间间隔
using namespace std;

int main()
{
  int sock;
  struct sockaddr_in mcast_addr;
  sock=socket(AF_INET,SOCK_DGRAM,0);
  if(sock==-1){
    cout<<"socket error"<<endl;
    return -1;
  }
  memset(&mcast_addr,0,sizeof(mcast_addr));
  mcast_addr.sin_family=AF_INET;
  mcast_addr.sin_addr.s_addr=inet_addr(MCAST_ADDR);
  mcast_addr.sin_port=htons(MCAST_PORT);
  while(1)
  {       //向局部多播地址发送多播内容
    int n=sendto(sock,MCAST_DATA,sizeof(MCAST_DATA),0,(struct sockaddr*)&mcast_addr,sizeof(mcast_addr));
    if(n<0){
      cout<<"send error"<<endl;
      return -2;
    }else{
      cout<<"send message is going ...."<<endl;
    }
    sleep(MCAST_INTERVAL);
  }
  return 0;
}

客户端:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#define MCAST_PORT 8888
#define MCAST_ADDR "224.0.0.88" /*一个局部连接多播地址,路由器不进行转发*/
#define MCAST_INTERVAL 5  //发送时间间隔
#define BUFF_SIZE 256   //接收缓冲区大小
using namespace std;
int main()
{
  int sock;
  struct sockaddr_in local_addr;
  int err=-1;
  sock=socket(AF_INET,SOCK_DGRAM,0);
  if(sock==-1){
     cout<<"sock error"<<endl;
      return -1;
   }
   /*初始化地址*/
   local_addr.sin_family=AF_INET;
   local_addr.sin_addr.s_addr=htonl(INADDR_ANY);
   local_addr.sin_port=htons(MCAST_PORT);
   /*绑定socket*/
   err=bind(sock,(struct sockaddr*)&local_addr,sizeof(local_addr));
   if(err<0){
     cout<<"bind error"<<endl;
     return -2;
   }
   /*设置回环许可*/
   int loop=1;
   err=setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));
   if(err<0){
     cout<<"set sock error"<<endl;
     return -3;
   }
   struct ip_mreq mreq;/*加入广播组*/
   mreq.imr_multiaddr.s_addr=inet_addr(MCAST_ADDR);//广播地址
   mreq.imr_interface.s_addr=htonl(INADDR_ANY); //网络接口为默认
   /*将本机加入多播组*/
   err=setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
   if(err<0){
     cout<<"set sock error"<<endl;
       return -4;
   }
          int times=0;
  socklen_t addr_len=0;
  char buff[BUFF_SIZE];
  int n=0;
  /*循环接受广播组的消息,5次后退出*/
  for(times=0;;times++)
  {
    addr_len=sizeof(local_addr);
    memset(buff,0,BUFF_SIZE);
    n=recvfrom(sock,buff,BUFF_SIZE,0,(struct sockaddr*)&local_addr,&addr_len);
    if(n==-1){
      cout<<"recv error"<<endl;
      return -5;
    }
    /*打印信息*/
    printf("RECV %dst message from server : %s\n",times,buff);
    sleep(MCAST_INTERVAL);
  }
   /*退出多播组*/  err=setsockopt(sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(mreq));
  close(sock);
  return 0;
}

3 Onvif协议

  Onvif协议是Open Network Video Interface Forum(开放型网络视频接口论坛)的英文缩写。

  ONVIF标准将为网络视频设备之间的信息交换定义通用协议,包括装置搜寻、实时视频、音频、元数据和控制信息等。网络视频产品由此所能提供的多种可能性,使终端用户,集成商,顾问和生产厂商能够轻松地从中获益,并获得高性价比、更灵活的解决方案、市场扩张的机会以及更低的风险。

视频设备发现代码示例:

#include "wsdd.h"
#include <stdio.h>

static struct soap* ONVIF_Initsoap(struct SOAP_ENV__Header *header, const char *was_To, const char *was_Action, int timeout)
{
    struct soap *soap = NULL;
    unsigned char macaddr[6];
    char _HwId[1024];
    unsigned int Flagrand;
    soap = soap_new();
    if(soap == NULL)
    {
        printf("[%d]soap = NULL\n", __LINE__);
        return NULL;
    }

    soap_set_namespaces( soap, namespaces);

    if (timeout > 0)
    {
        soap->recv_timeout = timeout;
        soap->send_timeout = timeout;
        soap->connect_timeout = timeout;
    }
    else
    {
        //Maximum wait time: 20S
        soap->recv_timeout    = 20;
        soap->send_timeout    = 20;
        soap->connect_timeout = 20;
    }
    soap_default_SOAP_ENV__Header(soap, header);

    // Create SessionID randomly
    srand((int)time(0));
    Flagrand = rand()%9000 + 8888;
    macaddr[0] = 0x1; macaddr[1] = 0x2; macaddr[2] = 0x3; macaddr[3] = 0x4; macaddr[4] = 0x5; macaddr[5] = 0x6;
    sprintf(_HwId,"urn:uuid:%ud68a-1dd2-11b2-a105-%02X%02X%02X%02X%02X%02X",
            Flagrand, macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
    header->wsa__MessageID =(char *)malloc( 100);
    memset(header->wsa__MessageID, 0, 100);
    strncpy(header->wsa__MessageID, _HwId, strlen(_HwId));

    if (was_Action != NULL)
    {
        header->wsa__Action =(char *)malloc(1024);
        memset(header->wsa__Action, ‘\0‘, 1024);
        strncpy(header->wsa__Action, was_Action, 1024);//"http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
    }
    if (was_To != NULL)
    {
        header->wsa__To =(char *)malloc(1024);
        memset(header->wsa__To, ‘\0‘, 1024);
        strncpy(header->wsa__To,  was_To, 1024);//"urn:schemas-xmlsoap-org:ws:2005:04:discovery";
    }
    soap->header = header;
    return soap;
} 

int ONVIF_ClientDiscovery( )
{
    int FoundDevNo = 0;
    int retval = SOAP_OK;
    wsdd__ProbeType req;
    struct __wsdd__ProbeMatches resp;
    wsdd__ScopesType sScope;
    struct SOAP_ENV__Header header;
    struct soap* soap;

    const char *was_To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
    const char *was_Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
    //IP Adress and PortNo, broadCast
    const char *soap_endpoint = "soap.udp://239.255.255.250:3702/";

    //Create new soap object with info
    soap = ONVIF_Initsoap(&header, was_To, was_Action, 10);

    soap_default_SOAP_ENV__Header(soap, &header);
    soap->header = &header;

    soap_default_wsdd__ScopesType(soap, &sScope);
    sScope.__item = "";
    soap_default_wsdd__ProbeType(soap, &req);
    req.Scopes = &sScope;
    req.Types = ""; //"dn:NetworkVideoTransmitter";

    //sent the message broadcast and wait
    retval = soap_send___wsdd__Probe(soap, soap_endpoint, NULL, &req);
    while (retval == SOAP_OK)
    {
        retval = soap_recv___wsdd__ProbeMatches(soap, &resp);
        if (retval == SOAP_OK)
        {
            if (soap->error)
            {
                printf("[%d]: recv soap error :%d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
                retval = soap->error;
            }
            else //we find a device
            {
                FoundDevNo ++;
                if (resp.wsdd__ProbeMatches->ProbeMatch != NULL && resp.wsdd__ProbeMatches->ProbeMatch->XAddrs != NULL)
                {
                    printf("****** No %d Devices Information ******\n", FoundDevNo );
                    printf("Device Service Address  : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs);
                    printf("Device EP Address       : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address);
                    printf("Device Type             : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Types);
                    printf("Device Metadata Version : %d\r\n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion);
                    //sleep(1);
                }
            }
        }
        else if (soap->error)
        {
            if (FoundDevNo == 0)
            {
                printf("No Device found!\n");
                retval = soap->error;
            }
            else
            {
                printf("Search end! Find %d Device! \n", FoundDevNo);
                retval = 0;
            }
            break;
        }
    }

    soap_destroy(soap);
    soap_end(soap);
    soap_free(soap);

    return retval;
}

int main(void )
{

    if (ONVIF_ClientDiscovery() != 0 )
    {
        printf("discovery failed!\n");
        return -1;
    }

    return 0;
}

参考文献:

【1】https://blog.csdn.net/laczf/article/details/47731917

【2】https://baike.baidu.com/item/%E5%A4%9A%E6%92%AD/6867723?fr=aladdin

【3】https://www.cnblogs.com/jingliming/p/4477264.html#_lab2_1_0

【4】https://blog.csdn.net/saloon_yuan/article/details/27524875

原文地址:https://www.cnblogs.com/ziyu-trip/p/8724725.html

时间: 2024-10-08 18:46:22

设备发现协议的相关文章

生成树协议、CDP思科设备发现协议、SSH协议

线路冗余->交换机成环 交换机成环导致: 1 广播风暴 2 mac地址表震荡 一个mac在一台交换机上只能对应一个接口,但一个接口可以对应多个mac 3 重复帧拷贝 生成树协议: 802.1D.PVST.PVST+.802.1s.802.1w 生成树协议用于实现二层线路冗余,在网络中逻辑的阻塞部分接口来实现从源到目的仅有一条唯一路径: 最佳路径故障时,阻塞端口自动工作来实现备份的作用: 所谓生成树,就是在二层网络中构建一个树形结构,形成唯一.最短.星型拓扑: 802.1D 公有 PDU:协议数据

局域网设备发现之Bonjour协议

本文由嵌入式企鹅圈原创团队成员-华南师范大学物联网创新中心Hende_Zhu先生执笔. WIFI物联网解决方案中,通常我们需要对设备进行绑定,需要通过某种方法先对设备进行发现,比如微信硬件采用广播的方式,定时向外发送上线消息或者采用一问一答的方式进行发现,Bonjour是由苹果公司实现的一种零配置网络(Zeroconf)协议,它是一种基于服务的设备发现协议,不仅能够自动获取有效IP地址,还可以通过查询服务的方式来找到设备地址,只要双方约定好服务(service)的名称,设备的IP地址和端口都是可

minidlna源码初探(二)—— SSDP设备发现的大致流程

前言: 之前有专文介绍了minidlna中的UPNP功能,内中介绍其中包含的SSDP(简单发现协议),SOAP(简单对象访问协议)等几个协议(http://blog.csdn.net/sakaue/article/details/19070735).本文将根据minidlna的程序流程,概述SSDP的流程,为下一部分ACE实现做铺垫. 设备发现的大致流程: 首先,根据UPNP的规范: 在设备加入网络,UPnP发现协议允许设备向控制点广告它的服务.它使用向一个标准地址和端口多址传送发现消息来实现.

微信硬件设备接入接口协议

微信硬件设备接入接口协议 (公开使用)Tencent Technologies Co., Ltd.腾讯科技有限公司All rights reserved产品版本 密级V2.0Beta 请输入密级:公开Tencent.腾讯科技有限公司项目名称: 微信硬件设备接入接口协议 共 页第 2 页 共 29页第 3 页 共 29页 文档历史记录第 4 页 共 29页部门 微信产品部\开放平台中心\平台开发组\架构优化组起始人员 koukoutan文档版本 描述 撰写人员 更新时间V1.0Beta 初稿 ko

SSDP 简单服务发现协议

SSDP 简单服务发现协议,是应用层协议,是构成UPnP(通用即插即用)技术的核心协议之一.它为网络客户端(network client)提供了一种发现网络服务(network services)的机制,采用基于通知和发现路由的多播方式实现. SSDP多播地址:239.255.255.250:1900(IPv4),FF0x::C(IPv6) 两种类型的SSDP请求消息会通过SSDP多播地址发送: 1. 发现请求(Discovery request 或查询请求).SSDP客户端向此地址发送HTTP

Onvif备忘录(2)----设备发现

续上篇,框架代码生成之后,就可以进行基于Onvif的开发了,先实现一个简单的设备发现的例子. VisualStudio中新建一个空白工程,将上篇中生成的框架代码添加进来,但soapServer.c文件中定义了许多要实现的函数,直接添加编译会报一大堆错误,且本例中只需要用到Client的功能,so ... 删掉soapServer.c, 留下soapClient.c即可. 工程结构如下: main.c代码如下: #include "wsdd.h" #include <stdio.h

【基础】华为设备RIP协议原理及配置全集

在做实验之前先介绍一下RIP协议的基本原理: 1.RIP是距离矢量协议:特点:把自己知道的所有路由的结果告诉自己的邻居.有两个版本,版本1和版本2.它们都以跳数作为度量值(AD是用来衡量路由协议的优劣的,AD值越小,越优先,METRIC是用来衡量同一路由协议学习到的,到达同一网段的路径的优劣的,越小越好),能够支持的最大跳数是15跳,第16跳就不可达.(经过一台路由器就是一跳) 2.版本一是有类路由协议:所谓有类是指,通过RIP版本一向邻居通告路由时,只能够携带有类网络号,而不能够携带掩码信息.

【中级】华为设备IS-IS协议配置实战

实验拓扑: 使用ENSP模拟器(版本V100R002C00 1.2.00.350) 实验要求: 1.通过IS-IS协议实现全网互通. 2.配置域间路由汇总. 3.配置不同协议间路由汇总. 4.配置IS-IS级别1和级别2之间路由重分发. 5.调整IS-IS的cost值. IS-IS基本原理: 1.IS-IS是链路状态路由协议,使用SPF算法计算出到达目的网络的最优路径生成路由表. 2.使用Hello包建立邻居关系,使用LSP交换链路状态信息,采用分层设计. 3.有两种路由选择级别,L1和L2,L

OSI各层对应设备及其协议

物理层:集线器(HUB).中继器 数据链路层:网桥.交换机,代表协议如SDLC.HDLC.PPP.STP.帧中继等 网络层:路由器.三层交换机,代表协议如IP.IPX.RIP.OSPF.ICMP.IGMP.ARP.RARP.BOOTP等 传输层:代表协议如TCP.UDP等 会话层:无 表示层:无 应用层:代表协议如http.Telnet.ftp.SNMP.DNS.SMTP.POP3等