前述链接在此~
TCP/IP协议与lwip库——源代码分析(一)
这一章会把lwip的初始化函数分析完毕,加油Ψ( ̄∀ ̄)Ψ
话说我立志每次换一个颜文字来写哈哈哈,看我能不能用完搜狗里面所有的颜文字~~
netif_init();
void netif_init(void)
{
#if LWIP_HAVE_LOOPIF
ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
IP4_ADDR(&loop_gw, 127,0,0,1);
IP4_ADDR(&loop_ipaddr, 127,0,0,1);
IP4_ADDR(&loop_netmask, 255,0,0,0);
#if NO_SYS
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
#else /* NO_SYS */
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
#endif /* NO_SYS */
netif_set_up(&loop_netif);
#endif /* LWIP_HAVE_LOOPIF */
}
LWIP_HAVE_LOOPIF
LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). This is only needed when no real netifs are available. If at least one other netif is available, loopback traffic uses this netif.
《TCP/IP详解》中这样说:
大多数产品都支持环回接口(Loopback Interface
),以允许运行在同一台主机上的客户程序和服务器程序通过TCP/IP进行通信,A类网络号127就是为环回接口预留的,大多数系统会把127.0.0.1分配给这个接口,并命名为localhost
在本应用中:
#define LWIP_HAVE_LOOPIF 0
所以实际上不会执行netif_init
中的任何语句,但我们还是来看看这个函数内部干了啥:
typedef struct ip_addr ip_addr_t;
ip_addr_t
是ip_addr
结构体的别称
/* This is the aligned version of ip_addr_t,
used as local variable, on the stack, etc. */
struct ip_addr {
u32_t addr; // 是ip_addr_t的对齐版本?使用局部变量,和栈
};
也就是说loop_ipaddr, loop_netmask, loop_gw;
分别包含一个32bit的地址
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
拆成四个部分(以.
为分割点)进行赋值,每个部分8bit
Add a network interface to the list of lwIP netifs.
// 代码有删减
struct netif *
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
{
// 参数说明:netif:预分配的netif结构; IP地址/掩码/网关;state:传递给新netif的不透明数据
// init:初始化接口的回调函数;input:pass的回调函数?
LWIP_ASSERT("No init function given", init != NULL);
/* reset new interface configuration state */
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
netif->dhcp = NULL;
#endif /* LWIP_DHCP */
/* remember netif specific state information data */
// 用于记录相关的信息
netif->state = state;
netif->num = netif_num++;
netif->input = input;
NETIF_SET_HWADDRHINT(netif, NULL);
netif_set_addr(netif, ipaddr, netmask, gw); // 核心代码,分析见下文
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) {
return NULL;
}
/* add this netif to the list */
netif->next = netif_list;
netif_list = netif;
snmp_inc_iflist();
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
netif->name[0], netif->name[1]));
ip_addr_debug_print(NETIF_DEBUG, ipaddr);
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
ip_addr_debug_print(NETIF_DEBUG, netmask);
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
ip_addr_debug_print(NETIF_DEBUG, gw);
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
return netif;
}
结构体定义:
/** Function prototype for netif init functions. Set up flags and output/linkoutput
* callback functions in this function.
* netif初始化函数的函数原型。 在此函数中设置标志和output / linkoutput回调函数。
* @param netif The netif to initialize
*/
typedef err_t (*netif_init_fn)(struct netif *netif);
err_t
= s8_t
= signed char
struct netif *netif
是一个结构体指针,*netif_init_fn
也是一个指针,这个指针指向一个函数,函数的输入参数是上述的结构体指针,返回值是有符号字符类型;这里涉及到typedef
的非通用用法:为复杂的声明定义一个简单的别名
(复杂声明的看法:从左到右,看到)就返回,往左看,再往右看()就表示是函数,再往左看…)
那么netif
这个结构体中包含什么呢?比较复杂:
// 代码有删减
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
// 所有lwip网络接口的通用数据结构,设备驱动程序的初始化功能应填写以下字段:hwaddr_len,hwaddr [],mtu,flags
struct netif {
struct netif *next; /** pointer to next in linked list 可以看出来是一个链接组织结构*/
/** IP address configuration in network byte order */
ip_addr_t ip_addr;
ip_addr_t netmask;
ip_addr_t gw;
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
netif_input_fn input; // 网络设备驱动程序调用此函数以将数据包向上传递到TCP/IP堆栈,也就是将网卡接收数据交给IP层,注意这是一个回调函数
/** This function is called by the IP module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
netif_output_fn output; // IP模块要在接口上发送数据包时,会调用此功能,通常首先解析硬件地址,然后发送数据包
// 这个一般会使用etharp.c中的etharp_output函数
/** This function is called by the ARP module when it wants
* to send a packet on the interface. This function outputs
* the pbuf as-is on the link medium. */
netif_linkoutput_fn linkoutput; // ARP模块发送数据包函数
/** This field can be set by the device driver and could point
* to state information for the device. */
void *state; // 该字段可以由设备驱动程序设置,并且可以指向设备的状态信息。
#if LWIP_DHCP
/** the DHCP client state information for this netif */
struct dhcp *dhcp;
#endif /* LWIP_DHCP */
/** maximum transfer unit (in bytes) */
u16_t mtu; // 最大传输单元(按字节)以太网为1500
/** number of bytes used in hwaddr */
u8_t hwaddr_len; // 硬件地址长度
/** link level hardware address of this interface */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; // 接口的连接层硬件地址(MAC地址) NETIF_MAX_HWADDR_LEN = 6
/** flags (see NETIF_FLAG_ above) */
u8_t flags; // 标志位,表示网卡需要什么样的功能
/** descriptive abbreviation */
char name[2]; // 描述缩写,网卡的名字
/** number of this interface */
u8_t num;
// 接口号,如果两个网络接口具有相同的描述缩写(即上面的name字段),就用num字段来区分相同类型的不同网络接口
};
这里是省略了使用SNMP
变量的部分
这是lwip的多网口设计,这里用netif
来描述每种网络接口(网卡)的特性,并且使用链表来管理,当上层有数据要发送的时候,lwip会从netif_list
中选择一个合适的网卡来将数据发送出去
下面就是设置地址的具体操作函数:
void netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw){
netif_set_ipaddr(netif, ipaddr);
netif_set_netmask(netif, netmask);
netif_set_gw(netif, gw);
}
netif_set_ipaddr
函数定义如下,用于重新设置网络接口的IP地址
// 代码有删减
void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) {
/* TODO: Handling of obsolete pcbs */
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
#if LWIP_TCP
struct tcp_pcb *pcb;
struct tcp_pcb_listen *lpcb;
/* address is actually being changed? */
if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
) {
/* this connection must be aborted */
struct tcp_pcb *next = pcb->next;
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
tcp_abort(pcb);
pcb = next;
} else {
pcb = pcb->next;
}
}
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
/* PCB bound to current local interface address? */
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
/* The PCB is listening to the old ipaddr and
* is set to listen to the new one instead */
ip_addr_set(&(lpcb->local_ip), ipaddr);
}
}
}
#endif
snmp_delete_ipaddridx_tree(netif);
snmp_delete_iprteidx_tree(0,netif);
/* set new IP address to netif */
ip_addr_set(&(netif->ip_addr), ipaddr);
snmp_insert_ipaddridx_tree(netif);
snmp_insert_iprteidx_tree(0,netif);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1_16(&netif->ip_addr),
ip4_addr2_16(&netif->ip_addr),
ip4_addr3_16(&netif->ip_addr),
ip4_addr4_16(&netif->ip_addr)));
}
我们看一下这段代码:
#if NO_SYS
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
#else /* NO_SYS */
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
#endif /* NO_SYS */
netif_set_up(&loop_netif);
NO_SYS = 0/1
的区别在于,最后一个回调函数不同,我们对照着来看:
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
......
netif->input = input;
也就是说用于将网卡数据交给ip层的回调函数不同,那么怎么个不同法:
第一个:(代码太长,此处就不贴上来了)
err_t ip_input(struct pbuf *p, struct netif *inp)
输入参数:pbuf
(用于管理数据包的结构体),netif
。输出参数是一个字符型变量
struct pbuf {
struct pbuf *next; // 链表组织结构,指向下一个数据包
void *payload; // 指向缓冲区中实际数据的指针
u16_t tot_len; // 此缓冲区以及链中属于同一数据包的所有下一个缓冲区的总长度
// p->tot_len == p->len + (p->next? p->next->tot_len: 0)
u16_t len; // 该缓冲区的总长度
u8_t /*pbuf_type*/ type; // pbuf_type as u8_t instead of enum to save space
u8_t flags; // misc flags
u16_t ref; // 引用计数始终等于引用此pbuf的指针的数量。
};
收到IP数据包时,网络接口设备驱动程序将调用此功能。 该函数对IP报头进行基本检查,例如数据包大小至少大于报头大小等。如果该数据包不是发给我们的,则转发该数据包(使用ip_forward)。 始终检查IP校验和。比如:
/* identify the IP header */
iphdr = (struct ip_hdr *)p->payload;
if (IPH_V(iphdr) != 4) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.err);
IP_STATS_INC(ip.drop);
snmp_inc_ipinhdrerrors();
return ERR_OK;
}
此处有对pbuf数据包的详细解释,马克以下~
而这个函数tcpip_input
不知道为啥没有办法找到定义
接下来就是打开一个接口,使能网卡,设置NETIF_FLAG_UP标志位,必须在网卡被使用前用户来调用
void netif_set_up(struct netif *netif)
主要的语句是下面这一句,用于打开网卡
if (!(netif->flags & NETIF_FLAG_UP)) {
netif->flags |= NETIF_FLAG_UP;
......
我们来看一下都有些什么样的flags
:
#define NETIF_FLAG_UP 0x01U
/*网络接口是否为“打开”状态。 这是一个软件标志,用于控制是否启用此网络接口并处理流量。 它由启动代码(用于静态IP配置)或分配地址后的dhcp / autoip设置。*/
#define NETIF_FLAG_BROADCAST 0x02U
// 设置则表明netif具有广播功能。由netif驱动程序在其init函数中进行设置
#define NETIF_FLAG_POINTTOPOINT 0x04U
// 如果设置,netif是点对点连接的一端。 由netif驱动程序在其init函数中设置
#define NETIF_FLAG_DHCP 0x08U
// 如果设置了接口,则使用DHCP配置接口。在启动或停止DHCP时由DHCP代码设置
#define NETIF_FLAG_LINK_UP 0x10U
/*如果设置了该接口,则该接口具有活动的链接(由网络接口驱动程序设置),或者由netif驱动程序在其init函数中设置(如果该链接当时处于打开状态),或者在该链接出现后的稍后时间设置(如硬件支持链接检测)*/
#define NETIF_FLAG_ETHARP 0x20U
// 如果设置,则netif是使用ARP的以太网设备。 由netif驱动程序在其init函数中设置。 用于检查输入数据包类型和DHCP的使用
#define NETIF_FLAG_ETHERNET 0x40U
// 如果设置,则netif是以太网设备。 如果仅用于PPPoE,则可能不使用ARP或TCP / IP
#define NETIF_FLAG_IGMP 0x80U
// 如果设置,则netif具有IGMP功能
接下来执行的是这一句:
etharp_gratuitous(netif);
解释一下什么叫做**Gratuitous ARP
:
当设备接入网络的时候,需要先发一个信息询问一下其它设备:我发的这个IP谁有?如果网络中存在该IP,则会回复;正式利用Gratuitous ARP
这个东西对回复进行判断**,如果接收到的响应或者回复,存在IP与设备自身相同,则标记为IP冲突;MAC冲突同理。
socket
在本应用中,LWIP_SOCKET
的宏定义值为0
那么什么事socket
通信呢?其实在python爬虫中,也会用到这个socket
,其实socket
就是TCP的介质,是TCP/IP协议的API(TCP是数据的介质)
LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
这篇文章有很详细的介绍
udp_init()/tcp_init()
void udp_init(void)
{
#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
}
LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS
:随机化第一个本地TCP / UDP pcb的本地端口(默认== 0),这样可以防止在引导设备后创建可预测的端口号
void tcp_init(void)
{
#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND)
tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */
}
也就是将第一个本地端口随机初始化的意思?
Dynamic Host Configuration Protocol:动态主机配置协议
特点是:局域网,基于UDP协议
用途是:内部网或网络服务供应商自动分配IP地址,给用户用于内部网管理员作为对所有计算机进行中央管理
来看启动网络接口的DHCP协商的代码:
err_t dhcp_start(struct netif *netif)
{
struct dhcp *dhcp;
err_t result = ERR_OK;
LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
dhcp = netif->dhcp;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
/* Remove the flag that says this netif is handled by DHCP,
it is set when we succeeded starting. */
netif->flags &= ~NETIF_FLAG_DHCP; // 删除表示该netif由DHCP处理的标志,它是在成功启动后设置的。
/* check hwtype of the netif */
if ((netif->flags & NETIF_FLAG_ETHARP) == 0) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n"));
return ERR_ARG;
}
/* check MTU of the netif MTU:最大传输单元*/
if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
return ERR_MEM;
}
/* no DHCP client attached yet? */
if (dhcp == NULL) { // 检测没有DHCP客户端连接
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); // 内存分配
if (dhcp == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
return ERR_MEM; // 表示内存溢出
}
/* store this dhcp client in the netif */
netif->dhcp = dhcp;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
/* already has DHCP client attached */
} else {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n"));
if (dhcp->pcb != NULL) {
udp_remove(dhcp->pcb);
}
LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL );
}
/* clear data structure */
memset(dhcp, 0, sizeof(struct dhcp)); // 清除数据结构中原有的数据,全部置0
/* dhcp_set_state(&dhcp, DHCP_OFF); */
/* allocate UDP PCB */
dhcp->pcb = udp_new(); // 注意这里使用的是UDP协议
if (dhcp->pcb == NULL) {
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
return ERR_MEM;
}
ip_set_option(dhcp->pcb, SOF_BROADCAST);
/* set up local and remote port for the pcb 设置pcb的本地和远程端口*/
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); // DHCP_CLIENT_PORT = 68
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); // DHCP_SERVER_PORT = 67
/* set up the recv callback and argument */
udp_recv(dhcp->pcb, dhcp_recv, netif);
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
/* (re)start the DHCP negotiation */
result = dhcp_discover(netif);
if (result != ERR_OK) {
/* free resources allocated above */
dhcp_stop(netif);
return ERR_MEM;
}
/* Set the flag that says this netif is handled by DHCP. */
netif->flags |= NETIF_FLAG_DHCP;
return result;
}
DHCP获取IP地址的4个步骤:discover->offer->request->ack
可以稍微记一下DHCP协议中的报文:
DHCP DISCOVER
:客户开始DHCP过程发送的包,是DHCP协议的开始DHCP OFFER
:服务器接收到DISCOVER
之后做出的响应,包括给与客户端的IP、客户端的MAC地址、租约过期时间、服务器的识别符等DHCP REQUEST
:客户端对于服务器发出的OFFER
的响应,在续约租期的时候也会使用DHCP ACK
:服务器接收到客户端发来的REQUEST
之后发出的成功确认的报文,建立连接的时候,客户端接收到这个报文之后才会确认分配给他的IP和其他信息可以被允许使用DHCP NAK
:ACK
相反的报文,表示服务器拒绝了客户端的请求DHCP RELEASE
:一般出现在客户端关机、下线等情况,会使DHCP服务器释放发出此报文的客户端的IP地址DHCP INFORM
:客户端发出的向服务器请求一些信息的报文DHCP DECLINE
:当客户端发现服务器分配的IP地址无法使用时,会发出此报文那么这里为什么只用了dhcp_discover(netif);
这样一个函数呢?
因为这个DHCP的配置啊哈哈哈哈哈~也就是说还没发送数据的那一块,就只做了第一步
所以我们可以看到在dhcp_recv
函数中有:
dhcp_handle_offer(netif);
dhcp_handle_ack(netif);
这样的调用情况
LWIP_DHCP
为1dhcp_start()
启动DHCPsys_check_timeouts();
函数处理内核各种定时事件代码有删减
struct dhcp{
/** transaction identifier of last sent request */
u32_t xid; // 随机生成的一段字符串,两个数据包拥有相同的xid说明他们属于同一次会话
/** our connection to the DHCP server */
struct udp_pcb *pcb;
/** incoming msg */
struct dhcp_msg *msg_in;
/** current DHCP state machine state */
u8_t state;
/** retries of current request */
u8_t tries;
u8_t subnet_mask_given;
struct pbuf *p_out; /* pbuf of outcoming msg */
struct dhcp_msg *msg_out; /* outgoing msg */
u16_t options_out_len; /* outgoing msg options length */
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
ip_addr_t server_ip_addr; /* dhcp server address that offered this lease 提供此租约的dhcp服务器地址*/
ip_addr_t offered_ip_addr;
ip_addr_t offered_sn_mask;
ip_addr_t offered_gw_addr;
u32_t offered_t0_lease; /* lease period (in seconds) 租约期(以秒为单位)*/
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) 建议的续订时间(通常为租赁期的50%)*/
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) 建议的重新绑定时间(通常为租赁期的66%)*/
};
初始化的话基本就是这些了,下篇文章会写echo的实现
这个板子现在有一个问题我记录一下,需要调试,就是用DMA直接进行网口传输的时候,板子的IP地址默认不是192.168.1.10会导致传输错误,但是相同的IP地址在lwip echo这个例程中是可以运行成功的,需要找一下原因了。
下面补充一个概念
SNMP
Simple Network Management Protocol:简答网络管理协议
基于TCP/IP的网络管理包含两个部分:网络管理站(也叫管理进程,manager
),和被管的网络单元(也叫被管设备,包括路由器、打印机等等,共同点是都运行TCP/IP协议,)被管设备端与管理相关的软件叫做代理程序或代理进程。
管理进程与代理进程之间的通信方式
一是管理进程向代理进程发出请求,询问一个具体的参数值
二是代理进程主动向管理进程报告有某些重要的事情发生
基于TCP/IP的网络管理包含3个组成部分:
get - request
:从代理进程处提取一个或多个参数值get - next - request
:从代理进程处提取一个或多个参数值的下一个参数值set - request
:设置代理进程的一个或多个参数值get - response
:返回的一个或多个参数值trap
:代理进程主动发出,通知管理进程有某些事情发生trap
使用的是UDP的162端口报文中的具体参数解释