zoukankan      html  css  js  c++  java
  • Linux C Socket 编程

    1 Socket 是什么

    Socket(套接字),就是对 网络上进程通信端点抽象。一个 Socket 就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制

    从所处的位置来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信交互的接口。如下图所示:

    2 Socket 类型

    2.1 标准套接字

    标准套接字是在传输层使用的套接字,分为流式套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)。

    标准套接字在接收和发送时只能操作数据部分(TCP Payload / UDP Payload),而不能对 IP 首部或TCP 首部和 UDP 首部进行操作。

    2.1.1 流套接字(SOCK_STREAM)

    流套接字(SOCK_STREAM)用于提供 面向连接(可靠)的数据传输服务。

    流套接字保证数据能够实现无差错、无重复发数据,并按顺序接收。

    流套接字(SOCK_STREAM)使用 TCP(The Transmission Control Protocol)协议 进行数据的传输

    2.1.2 数据报套接字(SOCK_DGRAM)

    数据报套接字(SOCK_DGRAM)用于提供 无连接(不可靠)的数据传输服务。

    数据报套接字不保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。

    数据报套接字(SOCK_DGRAM)使用 UDP(User DatagramProtocol)协议 进行数据的传输

    2.2 原始套接字(SOCK_RAW)

    原始套接字(SOCK_RAW)可以做到标准套接字做到的事,更可以做到标准套接字做不到的事。

    原始套接字是在传输层及传输层以下使用的套接字。

    原始套接字在接收和发送时不仅能操作数据部分(TCP Payload / UDP Payload),也能对 IP 首部或TCP 首部和 UDP 首部进行操作。

    因此如果我们开发的是更底层的应用,比如发送一个自定义的 IP 包、UDP 包、TCP 包或 ICMP 包,捕获所有经过本机网卡的数据包(sniffer),伪装本机的 IP ,拒绝服务攻击(DOS)等,都可以通过原始套接字(SOCK_RAW)实现。

    注意:必须在管理员权限下才能使用原始套接字。

    3 Socket() 函数 介绍

    3.1 功能

    分配文件描述符,创建 socket,即创建网络上进程通信的端点。

    3.2 头文件

    #include <sys/types.h>
    #include <sys/socket.h>
    

    3.3 函数原型

    int socket(int domain, int type, int protocol)

    3.4 参数

    注意:type 和 protocol 不可以随意组合,如 SOCK_STREAM 不可以跟 IPPROTO_UDP 组合。

    具体的组合和应用场景可以参考 4 创建 Socket 及其应用场景

    3.4.1 domain

    domain:即协议域,又称为协议族(family),如下所示:

    • AF_INET / PF_INET(2):IPv4,获取 网络层的数据

    • AF_INET6:IPv6

    • AF_UNIX:UNIX 系统本地通信

    • AF_PACKET / PF_PACKET(17):以太网包,获取 数据链路层的数据

    注:

    1. AF = Address Family(地址族),PF = Protocol Family(协议族)

    2. 理论上建立 socket 时是指定协议,应该用 PF_xxxx,设置地址时应该用 AF_xxxx。当然 AF_xxxx和 PF_xxxx 的值是相同的,混用也不会有太大的问题。

    3.4.2 type

    type:指定 socket 类型,如下所示:

    • SOCK_STREAM(1):面向连接的流式套接字(TCP)

    • SOCK_DGRAM(2):面向无连接的数据包套接字(UDP)

    • SOCK_RAW(3):接收 底层数据报文 的原始套接字

    • SOCK_PACKET(10):过时类型,可以使用,但是已经废弃,以后不保证还能支持,不推荐使用。

    3.4.3 protocol

    protocol:指定协议,如下所示:

    • 0:自动选择 type 类型对应的默认协议。

    • IPPROTO_IP(0):接受 TCP 类型的数据帧

    • IPPROTO_ICMP(1):接受 ICMP 类型的数据帧

    • IPPROTO_IGMP(2)接受 IGMP 类型的数据帧

    • IPPROTO_TCP(6):接受 TCP 类型的数据帧

    • IPPROTO_UDP(17):接受 UDP 类型的数据帧

    • ETH_P_IP(0x800):接收发往本机 MAC 的 IP 类型的数据帧

    • ETH_P_ARP(0x806):接受发往本机 MAC 的 ARP 类型的数据帧

    • ETH_P_RARP(0x8035):接受发往本机 MAC 的 RARP 类型的数据帧

    • ETH_P_ALL(0x3):接收发往本机 MAC 的所有类型 IP ARP RARP 的数据帧,接收从本机发出的所有类型的数据帧。(混杂模式打开的情况下,会接收到非发往本地 MAC 的数据帧)

    3.5 返回值

    • 成功:返回一个文件描述符

    • 失败:返回 -1,并设置 errno

    3.6 备注

    详情查看 man 手册:man 2 socket

    4 创建 Socket 及其应用场景

    5 bind() 函数

    5.1 功能

    将 IP 地址信息绑定到 socket。

    5.2 头文件

    #include <sys/types.h>          
    #include <sys/socket.h>
    

    5.3 函数原型

    int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

    5.4 参数

    5.4.1 sockfd

    通信 socket

    5.4.2 addr

    要绑定的地址信息(包括IP地址,端口号)。

    通用地址结构体定义:

    struct sockaddr 
    {
        sa_family_t sa_family;   // 地址族, AF_xxx
        char        sa_data[14]; // 包括 IP 和端口号
    }
    

    新型的地址结构体定义:(查看新型的结构体信息: gedit /usr/include/linux/in.h )

    struct sockaddr_in 
    {
      __kernel_sa_family_t    sin_family;    // 地址族,IP 协议。默认:AF_INET
      __be16                  sin_port;      // 端口号
      struct in_addr          sin_addr;      // 网络 IP 地址
    
      unsigned char           __pad          // 8 位的预留接口
    };
    

    5.4.3 addrlen

    地址信息大小

    5.5 返回值

    • 成功:返回 0

    • 失败:返回 -1,并设置 errno

    5.6 备注

    详细查看 man 手册:man 2 bind

    6 listen() 函数

    6.1 功能

    监听指定端口,socket() 创建的 socket 是主动的,调用 listen 使得该 socket 成为 监听 socket ,变主动为被动。

    6.2 头文件

    #include <sys/socket.h>

    6.3 函数原型

    int listen(int sockfd, int backlog);

    6.4 参数

    6.4.1 sockfd

    通信 socket

    6.4.2 backlog

    同时能处理的最大连接要求

    6.5 返回值

    • 成功:返回 0

    • 失败:返回 -1,并设置 errno

    6.6 备注

    详细查看 man 手册:man 2 listen

    7 accept() 函数

    7.1 功能

    提取出 监听 socket 的等待连接队列中 第一个连接请求,创建 一个新的 socket,即 连接 socket

    新建立的 连接 socket 用于发送数据和接受数据。

    7.2 头文件

    #include <sys/socket.h>

    7.3 函数原型

    #include <sys/types.h>          
    #include <sys/socket.h>
    

    7.4 参数

    7.4.1 sockfd

    监听 socket,即 在 调用 listen() 后的 监听 socket。

    7.4.2 addr

    (可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。

    7.4.3 addrlen

    (可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。

    7.5 返回值

    • 成功:指向 新的 socket(连接 socket)的文件描述符。

    • 失败:返回 -1,并设置 errno

    7.6 备注

    详细查看 man 手册:man 2 listen

    8 connect() 函数

    8.1 功能

    发送连接请求

    8.2 头文件

    #include <sys/types.h>          
    #include <sys/socket.h>
    

    8.3 函数原型

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    8.4 参数

    8.4.1 sockfd

    通信 socket

    8.4.2 addr

    要连接的服务器地址

    8.4.3 addrlen

    地址信息大小

    8.5 返回值

    • 成功:返回 0

    • 失败:返回 -1,并设置 errno

    8.6 备注

    详细查看 man 手册:man 2 connect

    9 sendto() 函数

    9.1 功能

    将数据由指定的 socket 传给对方主机

    9.2 头文件

    #include <sys/types.h>          
    #include <sys/socket.h>
    

    9.3 函数原型

    int sendto (int sockfd , const void * msg, int len, unsigned int flags, const
    struct sockaddr * to , int tolen);
    

    9.4 参数

    9.4.1 sockfd

    已建立连接的 socket,如果利用 UDP 协议则不需建立连接。

    9.4.2 msg

    发送数据的缓冲区。

    9.4.3 len

    缓冲区长度。

    9.4.4 flags

    调用方式标志位,一般设为 0 。

    9.4.5 to

    用来指定要传送的网络地址,结构 sockaddr

    9.4.6 tolen

    sockaddr 的长度

    9.5 返回值

    • 成功:返回实际传送出去的字符数

    • 失败:返回 -1,并设置 errno

    9.6 备注

    详细查看 man 手册:man 2 sendto

    10 recvfrom() 函数

    10.1 功能

    接收远程主机经指定的 socket 传来的数据,并把数据传到由参数 buf 指向的内存空间。

    10.2 头文件

    #include <sys/types.h>          
    #include <sys/socket.h>
    

    10.3 函数原型

    int recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,int *fromlen);

    10.4 参数

    10.4.1 sockfd

    已建立连接的 socket,如果利用 UDP 协议则不需建立连接。

    10.4.2 buf

    接收数据缓冲区。

    10.4.3 len

    缓冲区长度。

    10.4.4 flags

    调用方式标志位,一般设为 0 。

    10.4.5 from

    (可选)指针,指向装有源地址的缓冲区,结构 sockaddr

    10.4.6 fromlen

    (可选)指针,指向 from 缓冲区长度值,sockaddr 的结构长度

    10.5 返回值

    • 成功:返回实际接受到的字符数

    • 失败:返回 -1,并设置 errno

    10.6 备注

    详细查看 man 手册:man 2 recvfrom

    11 字节序

    字节序,是 大于一个字节类型的数据在内存中的存放顺序,由 CPU 架构决定,与操作系统无关。是在跨平台和网络编程中,时常要考虑的问题。

    11.1 高低地址

    在内存中,栈是向下生长的,以char arr[4]为例,(因为 char 类型数据只有一个字节,不存在字节序的问题)依次输出每个元素的地址,可以发现,arr[0] 的地址最低,arr[3] 的地址最高,如图:

    11.2 高低字节

    在十进制中靠左边的是高位,靠右边的是低位,在其他进制也是如此。

    例如: 0x12345678,从高位到低位的字节依次是 0x12、0x34、0x56 和 0x78。

    11.3 字节序分类 - 大小端模式

    字节序被分为两类:

    1. 大端模式(Big-endian):内存的 低地址 存放 数据的高字节,内存的 高地址 存放 数据的低字节。(与人类阅读顺序一致)

    2.** 小端模式**(Little-endian),是指内存的 低地址 存放 数据的低字节,内存的 高地址 存放 数据的高字节

    大端模式 CPU 代表是 IBM Power PC,小端模式 CPU 代表是 Intel X86、ARM。

    11.4 大小端示例

    以 0x12345678 为例,两种模式在内存中的存储情况,如下表所示:

    11.5 判断大小端

    利用 C 语言 union 联合体所有成员共用同一块内存的特性,可以用联合体快速实现判断大小端。

    #include <stdio.h>
    union u
    {
        char c[4];
        int i;
    };
    int main(void)
    {
        union u test;
        int j;
    
        test.i = 0x12345678;
    
        for(j = 0; j < sizeof(test.c); j++)
        {
            printf("0x%x
    ",test.c[j]);
        }
    
        return 0;
    }
    

    运行后结果:

    可以看出,我的机器是小端字节序。

    11.6 网络字节序与本机字节序

    网络字节序(NBO,Network Byte Order),是 TCP/IP 中规定好的一种数据表示格式。它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。

    网络字节序采用大端(Big-endian)字节序排序方式。

    主机字节顺序(HBO,Host Network Order),与机器 CPU 相关,数据的存储顺序由 CPU 决定。

    11.6.1 转换函数

    socket 编程中经常会用到 4 个网络字节顺序与本地字节顺序之间的转换函数:htons()、ntohl()、 ntohs()、htons()。

    htonl()--"Host to Network Long"        // 长整型数据主机字节顺序转网络字节顺序
    ntohl()--"Network to Host Long"        // 长整型数据网络字节顺序转主机字节顺序
    htons()--"Host to Network Short"       // 短整型数据主机字节顺序转网络字节顺序
    ntohs()--"Network to Host Short"       // 短整型数据网络字节顺序转主机字节顺序
    

    在使用小端字节序的系统中,这些函数会把字节序进行转换。

    在使用大端字节序的系统中,这些函数会定义成空宏。

    12 代码示例

    12.1 标准套接字(SOCK_STREAM - TCP)

    12.1.1 TCP Socket 通信过程

    12.1.1.1 服务器

    1. 建立连接阶段

    • 调用 socket(),分配文件描述符,创建 服务器 socket

    • 调用 bind(),将 socket 与本地 IP 地址和端口绑定

    • 调用 listen(),监听指定端口,socket() 创建的 socket 是主动的,调用 listen 使得该 socket 成为监听 socket ,变主动为被动

    • 调用 accept(),获得 连接 socket,阻塞等待客户端发起连接

    2. 数据交互阶段

    • 调用 read(),阻塞等待客户端发送的数据请求,收到请求后从 read() 返回,处理客户端请求

    • 调用 write(),将数据发送给客户端

    3. 关闭连接

    • 当 read() 返回 0 的时候,说明客户端发来了 FIN 数据包,即关闭连接,调用 close() 关闭 连接 socket 和 监听 socket

    12.1.1.2 客户端

    1. 建立连接阶段

    • 调用 socket(),分配文件描述符,创建 客户端 socket

    • 调用 connect(),向服务器发送建立连接请求

    2. 数据交互阶段

    • 调用 write(),向服务器发送数据

    • 调用 read(),阻塞等待服务器应答

    3. 关闭连接

    • 当没有数据发送的时候,调用 close() 关闭 客户端 socket ,即关闭连接,向服务器发送 FIN 数据报

    12.1.2 单个客户端单个服务器的 TCP 通信

    Linux-C TCP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144 - 例子1

    12.1.3 多线程实现 - 单个客户端单个服务器的 TCP 通信

    Linux-C TCP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144 - 例子2

    12.1.4 多路复用实现 - 单个客户端单个服务器的 TCP 通信

    Linux-C TCP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144 - 例子3

    12.1.5 多个客户端单个服务器的 TCP 通信

    Linux-C TCP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144 - 例子4

    12.1.6 多线程实现 - 多个客户端单个服务器的 TCP 通信

    Linux-C TCP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144 - 例子5

    12.1.7 多路复用实现 - 多个客户端单个服务器的 TCP 通信

    Linux-C TCP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144 - 例子6

    12.2 标准套接字(SOCK_DGRAM- UDP)

    12.2.1 UDP Socket 通信过程

    12.2.1.1 服务器

    1. 建立连接阶段

    • 调用 socket(),分配文件描述符,创建 服务器 socket

    • 调用 bind(),将 socket 与本地 IP 地址和端口绑定

    2. 数据交互阶段

    • 调用 recvfrom(),阻塞,接受客户端的数据

    • 调用 sendto(),将数据发送给客户端

    3. 关闭连接

    • 调用 close() 关闭 服务器 socket

    12.2.1.2 客户端

    1. 建立连接阶段

    • 调用 socket(),分配文件描述符,创建 客户端 socket

    2. 数据交互阶段

    • 调用 sendto(),向服务器发送数据

    • 调用 recvfrom(),阻塞,接受服务器的数据

    3. 关闭连接

    • 调用 close() 关闭 客户端 socket ,即关闭连接。

    12.2.2 单个客户端单个服务器的 UDP 通信

    代码来源:Linux-C UDP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540233 - 例子1

    12.2.3 多线程实现 - 单个客户端单个服务器的 UDP 通信

    代码来源:Linux-C UDP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540233 - 例子2

    12.2.4 多路复用实现 - 单个客户端单个服务器的 UDP 通信

    代码来源:Linux-C UDP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540233 - 例子3

    12.2.4 UDP 通信组播

    代码来源:Linux-C UDP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540233 - 例子4

    12.2.4 UDP 通信广播

    代码来源:Linux-C UDP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540233 - 例子5

    12.3 原始套接字

    12.3.1 抓取以太网上的所有数据帧

    代码来源:GitHub - zhouyingjiu - https://github.com/zouyingjiu/sniffer

    
    /* 
     *        sniffer.c 
     * 
     *        功能: 
     *                linux rawSocket 抓取以太网上的所有数据帧 
     * 
     *        参数: 
     *                无 
     * 
     *  注意: 
     *      执行该程序需要 root 权限 sudo ./  
     */ 
     
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
     
    #ifdef __linux__ 
            #include <unistd.h> 
            #include <errno.h> 
            #include <sys/socket.h> 
            #include <sys/types.h> 
            #include <netinet/in.h> 
            #include <netinet/ip.h> 
            #include <netinet/tcp.h> 
            #include <netinet/udp.h> 
            #include <netinet/ip_icmp.h> 
            #include <net/if_arp.h> 
            #include <netinet/if_ether.h> 
            #include <net/if.h> 
            #include <sys/ioctl.h> 
    #elif __win32__ 
            #include <windows.h> 
     
    #endif 
     
    void UnpackARP(char *buff); 
    void UnpackIP(char *buff); 
    void UnpackTCP(char *buff); 
    void UnpackUDP(char *buff); 
    void UnpackICMP(char *buff); 
    void UnpackIGMP(char *buff); 
     
    int main(int argc, char **argv) 
    { 
            int sockfd, i; 
            char buff[2048]; 
             
          /* 
           *   监听以太网上的所有数据帧 
           */ 
            if(0 > (sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))))         
            { 
                    perror("socket error!"); 
             
                    exit(-1); 
            } 
     
            while(1) 
            { 
                    memset(buff, 0, 2048); 
                     
                    int n = recvfrom(sockfd, buff, 2048, 0, NULL, NULL); 
     
                    printf("%s
    ",buff); 
                     
                    printf("开始解析数据包============
    "); 
                     
                    printf("大小: %d
    ", n); 
                     
                    struct ethhdr *eth = (struct ethhdr*)buff; 
                     
                    char *nextStack = buff + sizeof(struct ethhdr); 
                     
                    int protocol = ntohs(eth->h_proto); 
                    switch(protocol)  
                    { 
                            case ETH_P_IP: 
                                    UnpackIP(nextStack); 
                                    break; 
                             
                            case ETH_P_ARP: 
                                    UnpackARP(nextStack); 
                                    break; 
                    } 
                     
                    printf("解析结束=================
    
    "); 
            } 
     
            return 0; 
    } 
     
    void getAddress(long saddr, char *str)  
    { 
            sprintf(str, "%d.%d.%d.%d",                          
                            ((unsigned char*)&saddr)[0],          
                            ((unsigned char*)&saddr)[1],          
                            ((unsigned char*)&saddr)[2],          
                            ((unsigned char*)&saddr)[3]); 
    } 
     
    void UnpackARP(char *buff)  
    { 
            printf("ARP数据包
    "); 
    } 
     
    void UnpackIP(char *buff)  
    { 
            struct iphdr *ip = (struct iphdr*)buff; 
            char *nextStack = buff + sizeof(struct iphdr); 
            int protocol = ip->protocol; 
            char data[20]; 
     
            getAddress(ip->saddr, data); 
            printf("来源ip %s
    ", data); 
             
            bzero(data, sizeof(data)); 
     
            getAddress(ip->daddr, data); 
            printf("目标ip %s
    ", data); 
     
            switch(protocol) 
             { 
                    case 0x06: 
                            UnpackTCP(nextStack); 
                            break; 
     
                    case 0x17: 
                            UnpackUDP(nextStack); 
                            break; 
                     
                    case 0x01: 
                            UnpackICMP(nextStack); 
                            break; 
     
                    case 0x02: 
                            UnpackIGMP(nextStack); 
                            break; 
     
                    default: 
                            printf("unknown protocol
    "); 
                            break; 
            } 
    } 
     
    void UnpackTCP(char *buff)  
    { 
            struct tcphdr *tcp = (struct tcphdr*)buff; 
             
            printf("传输层协议:tcp
    "); 
         
            printf("来源端口:%d
    ", ntohs(tcp->source)); 
            printf("目标端口:%d
    ", ntohs(tcp->dest)); 
    } 
     
    void UnpackUDP(char *buff)  
    { 
            struct udphdr *udp = (struct udphdr*)buff; 
             
            printf("传输层协议:udp
    "); 
         
            printf("来源端口:%d
    ", ntohs(udp->source)); 
            printf("目的端口:%d
    ", ntohs(udp->dest)); 
    } 
     
    void UnpackICMP(char *buff)  
    { 
            printf("ICMP数据包
    ");         
    } 
     
    void UnpackIGMP(char *buff)  
    { 
            printf("IGMP数据包
    "); 
    } 
    

    12.3.2 抓取以太网上的所有数据帧,匹配 HTTP 协议并发送 TCP RST

    代码来源:我的 Github - https://github.com/PikapBai/sniffer_cmpHTTP_sendTCP

    13 参考资料

    1. 套接字 - 百度百科 - https://baike.baidu.com/item/套接字/9637606?fromtitle=socket&fromid=281150&fr=aladdin

    2. RAW SOCKET - 百度百科 - https://baike.baidu.com/item/RAW SOCKET/995623?fromtitle=原始套接字&fromid=23692610&fr=aladdin#ref_[1]_4263346

    3. 原始套接字简介 - chengqiuming - https://blog.csdn.net/chengqiuming/article/details/89577351

    4. 原始套接字概述 - anton_99 - https://blog.csdn.net/anton_99/article/details/95646879?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

    5. Linux 原始套接字抓取底层报文 - 2603898260 - https://blog.csdn.net/s2603898260/article/details/85020006?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

    6. Linux-C TCP 简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540144

    7. 【Linux网络编程】socket编程“网络字节顺序”和“主机字节顺序” - qq_20553613 - https://blog.csdn.net/qq_20553613/article/details/86385271

    8. 网络字节序 - 百度百科 - https://baike.baidu.com/item/网络字节序/12610557?fr=aladdin

    9. 字节序(大小端)理解 - sunflower_della - https://blog.csdn.net/sunflower_della/article/details/90439935

    10. 理解大小端字节序 - fan-yuan - https://www.cnblogs.com/fan-yuan/p/10406315.html

    11. linux网络编程之TCP/IP的TCP socket通信过程(含实例代码) - 知乎 - linux服务器开发专栏 - https://zhuanlan.zhihu.com/p/148739946

    12. Linux C Socket UDP编程详解及实例分享 - 知乎 - linux服务器开发专栏 - https://zhuanlan.zhihu.com/p/131402832

    13. Linux-C UDP简单例子 - nanfeibuyi - https://blog.csdn.net/nanfeibuyi/article/details/88540233

    14. 《图解 TCP/IP》(第 5 版)[日]竹下隆史 /[日]村山公保/ [日]荒井透 / [日]苅田幸雄

    15. 浅谈linux下原始套接字 SOCK_RAW 的内幕及其应用 - 知乎 - linux服务器开发专栏 - https://zhuanlan.zhihu.com/p/254912774

    16. GitHub - zhouyingjiu - https://github.com/zouyingjiu/sniffer

  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/PikapBai/p/13964866.html
Copyright © 2011-2022 走看看