协议

    常见协议
    应用层FTP(File Transfer Protocol 文件传输协议) 、HTTP协议(Hyper Text Transfer Protocol 超文本传输协议)、NFS(NetWork File System 网络文件系统)、SSH —sshd其对应的守护进程
    传输层 TCP(Transmission Control Protocol传输控制协议)、UDP(User Datagram Protocol用户数据报协议)
    网络层 IP(Internet Protocol因特网互联协议)、ICMP(Internet Control Message Protocol因特网控制报文协议)、IGMP(Internet Group Management Protocol因特网组管理协议)
    网络接口层
    ARP(Address Resolution Protocol地址解析协议),RARP(Reverse Address Resolution Protocol反向地址解析协议) 其实这两个协议是介于接口和网络层之间的.5层ARP协议是介于链路层和网络层之间的一个协议,你可以说它属于链路层,也可以说它属于网络层

    UDP协议
    0 15 16 31
    |16位源端口号 | 16位目的端口号.|
    32 47 48 63
    |16位UDP长度.| 16位UDP校验和| 协议头共64位 8字节
    | 传输的数据 | UDP长度为用户数据报长度 (首部8字节+传输大小)

    TCP协议
    tcp头部结构
    0 15 16 31
    |16位源端口号 | 16位目的端口号.|
    32 63
    | 32位序号 |
    64 95
    | 32位确认号 |
    96 99 100 105 106 107 108 109 110 111 112 127
    |四位头部长度|6位保留|URG|ACK|PSH|RST|SYN|FIN|16位窗口大小|
    128 143 159
    | 16位校验和 | 16位紧急指针|
    160
    | 选项最多40字节 |

    序列号:本报文段的数据的第一个字节的序号
    确认序号:期望收到对方下一个报文段的第一个字节的序号
    首部长度(数据偏移):以4字节位单位,最大1111— TCP首部最长154字节60字节
    保留:6位 保留为今后使用 目前置为0
    紧急URG:为1,表示紧急指针字段有效,表示此报文段中有紧急数据应尽快传送
    确认ACK: 为1 ,表示确认号字段有效,TCP规定在建立连接后所传达的所有报文段都必须把ACK置为1
    推送PSH:当两个应用进程进行交互式通信时,有时一端的应用希望在发送一个命令后立即就能收到对方的响应,在这种情况下将PSH置为1,并立即创建一个报文段发送出去,当接收方收到PSH=1的报文段,就会尽快地将响应发给请求端,而不再等到整个缓存都填满后再向上交付。
    RST:置1 复位相应的TCP连接
    同步SYN:仅再三次握手建立TCP连接时有效,当SYN=1 ACK=0时表示这是一个连接请求报文段,对方若同意建立连接,则应在响应报文中令SYN=1 ACK=1表示同意建立连接。即SYN=1表示这是一个连接请求或连接接受报文。
    终止FIN:置1 表明此报文段的发送方的数据已经发送完毕,并要求释放这个连接关系
    窗口:指发送本报文段的这方的接收窗口(而不是自己的发送窗口)
    校验和:检验首部和数据两部分。在计算校验和时需要加上12字节的伪头部
    紧急指针:仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据),即指出了紧急数据的末尾在报文中的位置,即使窗口为0时也可发送紧急数据
    选项:长度可变最长40字节






    IP协议
    ipv4头部结构
    0 3 4 7 8 15 16 31
    |4位版本号 |4位头部长度|8位服务类型(TOS)|16位总长度(字节数)|
    32 47 48 50 51 63
    | 16位标识|3位标志|13位片偏移|
    64 71 72 79 80 95
    |8位生存时间|8位协议|16位头部校验和|
    96 127
    |32位源IP地址|
    128 159
    |32位目的IP地址|
    160
    | 选项最多40字节 |

    版本:4 or 6,最常用还是4 ipv4
    首部长度:4位,单位是32位(4字节) 即首部最长15(1111)
    4=60字节
    服务类型:一般不使用 取0
    总长度:首部加上数据的总长度 单位字节
    标识:每产生一个数据报计数器就+1,这个值就是这个字段的值
    标志:目前只有前两位有意义 标志中的最低位为MF。MF=1表示后面还有分片的数据报。
    MF=0表示这已是若干数据报片中的最后一个。标志中的第二位为DF,DF=1表示此数据报不能分片,DF=0表示允许分片。
    片偏移:指出在分片后,某片在源分组中的相对位置。在原完整用户数据中,该片的起点在何处,以8字节为单位。
    生存时间TTL:由发出数据报的源设置这个字段,每经过一次路由器 路由器会将这个值减1,当TTL为0则丢弃这个数据。
    协议:指此数据报携带的数据使用何种协议。以便目的主机的网络层直到将数据部分用哪个协议来解析处理,常用的ICMP 1,IGMP 2,TCP 6,UDP 17,IPV6 41。上层使用的是什么协议
    (这样接收端在分用时才能找到对应的协议进一步解封装 得到上层的信息)


    以太网帧协议(链路层)
    |目的物理地址|源物理地址|类型|数据|CRC|
    6字节 6字节 2字节 46-1500字节 CRC 4字节校验位
    类型中0x800表示IP 0x806表示ARP 0x835表示RARP 类型表示的是上层使用的是什么协议
    (这样接收端在分用时才能找到对应的协议进一步解封装 得到上层的信息)
    注意这里的的数据可能是上层传下来封装好的IP数据报 在链路层再封装一层再发往物理层,也可能是ARP协议对应的数据
    ARP协议
    ARP根据子网中的IP地址获得对应的MAC地址
    RARP根据子网中的MAC地址获得对应的IP地址
    |硬件类型|协议类型|硬件地址长度|协议地址长度|操作|发送端以太网(MAC)地址 6字节|发送端IP地址 4字节|目的端以太网(MAC)地址 6字节|目的端IP地址 4字节|
    对于ARP来说目的端以太网(MAC)地址就是我要获得的目前未知 可以填个全0(ARP应答会将这个MAC给填上发还给我们)
    硬件地址:2字节 1表示MAC地址
    协议类型:2字节 表示是上层的使用了哪种协议 0x800表示IP协议 上层使用的是什么协议(这样接收端在分用时才能找到对应的协议进一步解封装 得到上层的信息)

    硬件地址长度:1字节 mac地址为6字节 所以这里是6(0000 0110)
    协议地址长度: 1字节 上层用IP协议 IP地址为4字节 所以这里是4(0000 0100)
    操作:2字节 1表示ARP请求 2表示ARP应答 3表示RARP请求 4表示RARP应答

    ARP协议长28个字节,在链路层需要给ARP报文的前后加上以太网帧的头和校验码再发送出去,例:若当前链路层网络类型为以太网,网络层协议为IP协议,
    以太网源地址为MAC1,源IP地址为IP1,
    以太网目的地址为MAC2,目的IP地址为IP2.
    则ARP请求帧应为: ARP应答帧:
    以太网目的地址:ff ff ff ff ff ff 以太网目的地址:MAC1
    以太网源地址:MAC1 以太网源地址:MAC2
    帧类型:0806 帧类型:0806
    硬件类型:以太网(0001) 硬件类型:以太网(0001)
    协议类型:IP协议(0800) 协议类型:IP协议(0800)
    硬件地址长度:6 个字节 硬件地址长度:6个字节
    协议地址长度: 4 个字节 协议地址长度:4个字节
    op: 1 op:2
    发送端以太网地址:MAC1 发送端以太网地址:MAC2
    发送端IP地址:IP1 发送端IP地址:IP2
    目的以太网地址:00 00 00 00 00 00 目的以太网地址:MAC1
    目的IP地址:IP2 目的IP地址:IP1
    封装
    引用程序在发送到物理网络之前,将沿着协议栈从上往下一次传递,每层协议都将在上层的数据(含头)的基础上加上自己的头部信息(有些协议还有尾部信息 比如以太网帧),以实现该层功能(使用下层的协议)。
    下面是一个TCP/IP的封装

    4 Linux网络编程2 常见协议及其格式,协议封装,字节序 - 图1

    发送端将数据封装好后发送

    分用(解封装)
    当帧到达目的主机时,将沿着上面这张图的协议栈 依靠头部结构中的信息依次将头部(尾部)去掉得到数据,再使用上层对应的协议进一步解封装取数据。

    4 Linux网络编程2 常见协议及其格式,协议封装,字节序 - 图2

    接收端将接收到的信息分用(解封装)

    TCP/IP封装与分用(解封装) app首部为某个应用层协议的首部

    4 Linux网络编程2 常见协议及其格式,协议封装,字节序 - 图3

    scoket
    所谓socket(套接字),就是对网络中不同主机上的应用程序进程之间进行双向通信节点的抽象,一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制,套接字是应用程序通过网络协议栈进行通信的接口。
    socket是进程间通信(同一台主机也可以是不同的主机的进程间通信)的API,可是可被命名和寻址的通信节点。每一个套接字都有其类型和一个与之相连的进程。socket套接字需要主机IP地址和进程所在端口号结合,提供应用层进程传输和接收数据的机制。
    在Linux环境下,socket是进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件,既然是文件我们就可以使用文件描述符fd来打开、读、写套接字。与管道类似,Linux将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。
    客户端socket主动向服务器发起连接

    字节序
    32位机的累加器一次能装载4字节,这四字节在内存中的排列顺序将影响它被累加器装载成的整数值。不同的计算机体系中对于字节、字节序的存储机制有所不同,这就引发了一个问题,即通信双方交流的信息单元(比特、字节、字)应该以什么样的顺序进行传输。达不成一致的规则,通信双方将无法进行正确的编译码从而导致通信失败。

    字节序 大于一个字节的类型的数据在内存中的存放顺序,(注意是四个字节的之间的顺序而不是位的顺序 位还是左(低位) 右(高位))
    大端字节序 整数的最高位字节(23-31位)存在内存的低地址处,低位字节(0-7位)存在内存的高地址处。
    小端字节序 整数的最高位字节(23-31位)存在内存的高地址处,低位字节(0-7位)存在内存的低地址处。

    0x1234567 (01是数据高位字节)
    低地址 高地址
    大端 01 23 45 67
    小端 67 45 23 01

    大部分计算机采用的是小段字节序

    1. union{//联合体
    2. short value;//2字节
    3. char bytes[sizeof(short)];//2字节
    4. }test;
    5. test.value = 0x0102;//两字节
    6. if(test.bytes[0]==1)
    7. //若数组中的第一位(索引为0是低地址处) 存的是01(数据的高位字节) 则是大端
    8. printf(“big end”);
    9. else if(test.bytes[0]==2)
    10. //若数组中的第一位(索引为0是低地址处) 存的是02(数据的低位字节) 则是小端
    11. printf(“small end”);
    4 Linux网络编程2 常见协议及其格式,协议封装,字节序 - 图4
    小端字节序 高地址放在高字节位
    4 Linux网络编程2 常见协议及其格式,协议封装,字节序 - 图5
    大端字节序 高地址放在低字节位
    1. 再举个例子
    2. union{//联合体
    3. int value;//4字节
    4. char bytes[sizeof(int)];//4字节
    5. }test;
    6. value = 20;
    7. bytes[0] = 0;
    8. bytes[1] = 10;


    //小端
    1.value = 20;//对小端来说低字节存在低地址,所以数组装载这个20时是优先从低地址开始装
    高地址 低地址
    bytes[3] bytes[2] bytes[1] bytes[0]
    0 0 0 0x14(20)
    2.bytes[0] = 0;
    高地址 低地址
    bytes[3] bytes[2] bytes[1] bytes[0]
    0 0 0 0
    按小端 低地址方低字节位。
    3.bytes[1] = 10;
    高地址 低地址
    bytes[3] bytes[2] bytes[1] bytes[0]
    0 0 0x0a 0
    按小端 低地址方低字节位。

    最后的数
    高地址 低地址
    00000000 00000000 00001010 0000000
    变回我们正常人习惯的阅读形式(也是系统print的顺序) 低地址在左 高地址在右
    低地址 高地址
    0000000 00001010 00000000 00000000
    最终0000000 00001010 00000000 00000000换成10进制是2560

    //大端
    1.value = 20;//对大端来说低字节存在高地址,所以数组装载这个20时是优先从高地址开始装
    高地址 低地址
    bytes[3] bytes[2] bytes[1] bytes[0]
    0x14(20) 0 0 0
    2.bytes[0] = 0;
    高地址 低地址
    bytes[3] bytes[2] bytes[1] bytes[0]
    0x14(20) 0 0 0
    3.bytes[1] = 10;
    高地址 低地址
    bytes[3] bytes[2] bytes[1] bytes[0]
    0x14(20) 0 0x0a 0
    按大端 低地址方高字节位。

    最后的数
    高地址 低地址
    00010100 00000000 00001010 0000000
    变回我们正常人习惯的阅读形式(也是系统print的顺序) 低地址在左 高地址在右
    低地址 高地址
    0000000 00001010 00000000 00010100
    最终0000000 00001010 00000000 00010100 换成10进制是655380