《TCP/IP详解,卷2:实现》读书笔记-以太网和IP

    我们先来回顾一下以太网帧的格式,以太网帧包括48bit的目标地址和源地址,接下来是一个16bit的类型字段,它标识这个帧所携带的数据的格式。对于IP分组,类型是0x0800(2048)。帧的最后是一个32bit的CRC(循环冗余检验),它用来检查帧中的差错。帧的格式如下图所示:

   

    我们用48bit的以太网地址作为硬件地址。IP地址到硬件地址之间的转换用ARP协议。而硬件地址到I P地址的转换用RARP协议。以太网地址有两种类型:单播和多播。一个单播地址描述一个单一的以太网接口,而一个多播地址描述一组以太网接口。一个以太网广播是一个所有接口都接收的多播。

    当一个完整的帧可用时,接口就产生一个中断,并且内核调用leintrleintr检测硬件,并且如果有一个帧到达,就调用leread把这个帧从接口转移到一个mbuf链中。如果硬件报告一个帧已传输完或发现一个差错(如一个有错误的检验和),则leintr更新相应的接口统计,复位这个硬件,并调用lestart来传输另一个帧。所有以太网设备驱动程序将它们接收到的帧传给ether_input做进一步的处理。设备驱动程序构造的mbuf链不包括以太网首部,以太网首部作为一个独立的参数传递给 ether_input

每个协议有它自己的地址格式。BSD在一个sockaddr结构中处理通用的地址。sa_len指示地址的长度(OSIUnix域协议有不同长度的地址)sa_family指示地址的类型。成员sa_lensa_family允许协议无关代码操作来自多个协议的变长的sockaddr结构。剩下的成员sa_data,包含一个协议相关格式的地址。sa_data定义为一个14字节的数组,但当sockaddr结构覆盖更大的内存空间时,sa_data可能会扩展到253字节。sa_len仅有一个字节,因此整个地址,包括sa_lensa_family必须不超过256字节。

这是C语言的一种通用技术,它允许程序员把一个结构中的最后一个成员看成是可变长的。

每个协议定义一个专用的sockaddr结构,该结构复制成员sa_lensa_family,但按那个协议的要求来定义成员sa_data。存储在sa_data中的地址是一个传输地址;它包含足够的信息来标识同一主机上的多个通信端点。在第6章我们要查看Internet地址结构sockaddr_in,它包含了一个IP地址和一个端口号。

    在以前的读书笔记中,描述了通用的sockaddrifaddr结构,很多做过socket编程的人对于这些结构 都比较陌生,因为这个是通过的结构,不仅仅IP协议会用到,其它协议也会用到,下面会讲到IP专用 的结构:sockaddr_inin_ifaddr。看到sockaddr_in,大家心中应该比较释然了,终于看到熟悉的结构了!
由于历史原因,BSD中以网络字节序将Internet地址存储在一个in_addr结构中。这个结构只有一个成员s_addr,它包含这个地址。注意,一般为了方便本地对地址的处理,地址一般是以主机 字节序存储的,这里是一个例外。
    这里讲到字节序问题,我们引申一下,大概的介绍一下字节序的基本概念:
    字节序有两种,大端字节序和小端字节序,IntelX86系列芯片是小端字节序,IBMPowerPC芯片是大 端字节序,所谓本机字节序,本机使用什么芯片,本机字节序就对应芯片的字节序,网络字节序对应大端 字节序。对于数值0x1234,小端字节序0x12放在高地址,0x34放在低地址,大端字节序0x12放在低地址,0x34放在高地址。  

struct  in_addr {
    u_long s_addr;
};

struct  sockaddr_in {
    u_char    sin_len;
    u_char    sin_family;
    u_short    sin_port;
    
struct     in_addr sin_addr;
    
char     sin_zero[ 8 ];
};


    in_ifaddr是为Internet协议定义的接口地址结构。对于每个指派给一个接口的IP地址,分配了一个in_ifaddr结构,并且添加到接口地址列表中和IP地址全局列表中。

struct  in_ifaddr {
    
struct     ifaddr ia_ifa;         /*  protocol-independent info  */
#define     ia_ifp        ia_ifa.ifa_ifp
#define  ia_flags    ia_ifa.ifa_flags
                    
/*  ia_{,sub}net{,mask} in host order  */
    u_long    ia_net;            
/*  network number of interface  */
    u_long    ia_netmask;        
/*  mask of net part  */
    u_long    ia_subnet;        
/*  subnet number, including net  */
    u_long    ia_subnetmask;        
/*  mask of subnet part  */
    
struct     in_addr ia_netbroadcast;  /*  to recognize net broadcasts  */
    
struct     in_ifaddr  * ia_next;     /*  next in list of internet addresses  */
    
struct     sockaddr_in ia_addr;     /*  reserve space for interface name  */
    
struct     sockaddr_in ia_dstaddr;  /*  reserve space for broadcast addr  */
#define     ia_broadaddr    ia_dstaddr
    
struct     sockaddr_in ia_sockmask;  /*  reserve space for general netmask  */
    
struct     in_multi  * ia_multiaddrs;  /*  list of multicast addresses  */
};

struct     in_aliasreq {
    
char     ifra_name[IFNAMSIZ];         /*  if name, e.g. "en0"  */
    
struct     sockaddr_in ifra_addr;
    
struct     sockaddr_in ifra_broadaddr;
#define  ifra_dstaddr ifra_broadaddr
    
struct     sockaddr_in ifra_mask;
};
    sin_len总是16(结构sockaddr_in的大小),并且sin_familyAF_INET
    sin_port是一个网络字节序(不是主机字节序)16bit值,用来分用运输层报文。sin_addr 标识一个32bitInternet地址。 
    
   

你可能感兴趣的:(《TCP/IP详解,卷2:实现》读书笔记-以太网和IP)