LinuxC—网络套接字

news2024/9/27 15:34:49

网络套接字socket

1 跨主机传输需要注意的问题

1.1 字节序问题

大端存储与小端存储

  • 大端:低地址处方高字节
  • 小端:低地址处方低字节

主机字节序和网络字节序

若两个主机的字节序存储方式不同,直接传输的数据被对方接收后会就会使完全错误的,为了避免这种情况发生,从而引入主机字节序(host)和网络字节序(network)。即网络中的数据传输用同一中网络字节序,各个主机提供主机字节序与网络字节序相互转换的接口:

  • hton(s/l) 主机转网络
  • ntoh(s/l) 网络转主机

1.2 对齐

比如对于下面的这个结构体:

struct {
    int i;
    float f;
    char ch;
}

他所占的字节内存空间并不是9个字节而是12个字节,这是因为编译器为了方便数据处理而采取了对齐处理,这样的一个结构体在不同的主机上的对齐方式可能不一样,从而导致传输的数据不能被正确的解析,所以应该让结构体不对齐

即在定义结构体的时候通过宏来告诉编译器不进行对齐处理

1.3 类型长度的问题

不同机器或编译器对于常用数据类型的长度的定义是不一样的,解决办法就是使用诸如以下的数据类型:

  • int32_t
  • uint32_t
  • int63_t

2 socket是什么

一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。

在这里插入图片描述

3 socket函数

  • socket()

    用domain协议族中的protocol协议来完成type类型的传输

int socket(int domain, int type, int protocol);
  • 成功返回一个socket文件描述符,否则返回-1并设置errno
  • domain的值
Name                Purpose                          Man page
AF_UNIX, AF_LOCAL   Local communication              unix(7)
AF_INET             IPv4 Internet protocols          ip(7)
AF_INET6            IPv6 Internet protocols          ipv6(7)
AF_IPX              IPX - Novell protocols
AF_NETLINK          Kernel user interface device     netlink(7)
AF_X25              ITU-T X.25 / ISO-8208 protocol   x25(7)
AF_AX25             Amateur radio AX.25 protocol
AF_ATMPVC           Access to raw ATM PVCs
AF_APPLETALK        AppleTalk                        ddp(7)
AF_PACKET           Low level packet interface       packet(7)
AF_ALG              Interface to kernel crypto API
  • type的值
SOCK_STREAM(流式)     Provides sequenced, reliable, two-way, connection-based byte streams.  An out-of-band data transmission mechanism may be supported.

SOCK_DGRAM(报式)      Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

SOCK_SEQPACKET  Provides  a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with
each input system call.

SOCK_RAW        Provides raw network protocol access.

SOCK_RDM        Provides a reliable datagram layer that does not guarantee ordering.

SOCK_PACKET     Obsolete and should not be used in new programs; see packet(7).

4 报式套接字UDP

4.1 基本过程

被动端(先运行)

  • 取得socket
  • 给socket取得地址
  • 收/发消息
  • 关闭socket

主动端

  • 取得socket
  • 给socket取得地址(可省略,系统给默认的端口)
  • 发/收消息
  • 关闭socket

4.2 相关函数

socket() 创建socket

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

bind() 绑定对应的端口

​ sockaddr这个结构体并不存在,需要根据我们socket中所采用的协议族来确定使用什么样的结构体,addrlen就是实际 使用的结构体的大小。成功返回0,失败返回-1并设置errno

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

​ 当采用AF_INET(ipv4)协议的时候,所使用的结构体为:

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET  协议族*/
    in_port_t      sin_port;   /* port in network byte order  绑定的端口*/
    struct in_addr sin_addr;   /* internet address ip地址*/
};

/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order 整型ip地址*/
};
  • 补充函数inet_pton()将点分的IPV4地址转换成一个整型,af是协议族,src是点分IPV4地址,dst是存放整型结果的地址
int inet_pton(int af, const char *src, void *dst);
  • inet_ntop() 将大整数IP地址转换成点分式
const char *inet_ntop(int af, const void *src,
                      char *dst, socklen_t size);

recvfrom()

​ 从sockfd中接受len字节的数据到buf中,flags为特殊要求,src_addr和addrlen是对端(发送端)地址和地址的长度的地 址

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

sendto()

​ 从sockfd中发送buf中len字节数据到网络中,flags为特殊要求,dest_addr和addrlen为接受端的地址和地址长度信息

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

close() 关闭socket

int close(int fd);

setsockopt() 设置socket的options,成功返回0,失败返回-1并设置errno

  • 对sockfd某一个层面level中的某一个属性optname进行设置
int setsockopt(int sockfd, int level, int optname,
               const void *optval, socklen_t optlen);		

getsockopt() 获取socket的options

int getsockopt(int sockfd, int level, int optname,
               void *optval, socklen_t *optlen);

4.3 报式传输实例

要传输的数据的格式

#ifndef SOCKET_PROTO_H
#define SOCKET_PROTO_H

#define NAMEMAX (512 - 8 - 8)
#define RCVPORT "1999"

struct msg_st {
    u_int32_t math;
    u_int32_t chinese;
    u_int8_t name[1];
} __attribute__((packed));

#endif //SOCKET_PROTO_H

接收方

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <string.h>
#include <unistd.h>

#include "proto.h"

#define IPSTRSIZE 64

int main() {
    int sd;
    struct sockaddr_in laddr, raddr;
    struct msg_st rbuf;
    socklen_t raddr_len;
    char ipstr[IPSTRSIZE];

    //1 取得socket用ipv4协议中默认支持报式传输的协议
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    //2 给socket绑定地址
    laddr.sin_family = AF_INET;
    laddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr);
    if (bind(sd, (void *) &laddr, sizeof (laddr)) < 0) {
        perror("bind()");
        exit(1);
    }
    //3 接受信息
    raddr_len = sizeof (raddr); /* 注意初始化发送端的地址长度!!! */
    while (1) {
        recvfrom(sd, &rbuf, sizeof (rbuf), 0, (void *) &raddr, &raddr_len);
        inet_ntop(AF_INET, &raddr.sin_addr.s_addr, ipstr, IPSTRSIZE);
        printf("---MSSAGE FROM %s:%d---\n", ipstr, ntohs(raddr.sin_port));
        printf("name = %s, math = %d, chinese = %d\n", rbuf.name, ntohl(rbuf.math), ntohl(rbuf.chinese));
    }
    //4 关闭socket
    close(sd);

    exit(0);
}

发送方

int main(int argc, char *argv[]) {

    int sd, size;
    struct msg_st *sbufp;
    struct sockaddr_in raddr;
    if (argc < 3) {
        fprintf(stderr, "Usage....\n");
        exit(1);
    }
    if (strlen(argv[2]) > NAMEMAX) {
        fprintf(stderr, "Name is too long...\n");
        exit(1);
    }
    //取得socket
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    //bind()
    //发送消息
    size = sizeof (struct msg_st) + strlen(argv[2]);
    sbufp = malloc(size);
    if (sbufp == NULL) {
        perror("malloc()");
        exit(1);
    }
    strcpy(sbufp->name, argv[2]);
    sbufp->chinese = htonl(rand() % 100);
    sbufp->math = htonl(rand() % 100);
    raddr.sin_family = AF_INET;
    raddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET, argv[1], &raddr.sin_addr.s_addr);
    if (sendto(sd, sbufp, size, 0, (void *) &raddr, sizeof (raddr)) < 0) {
        perror("sendto()");
        exit(1);
    }

    //关闭socket
    close(sd);

    exit(0);
}

4.4 广播实例

广播需要对发送方的实现进行修改,设置options并且将广播的地址设置为"255.255.255.255"

int main(int argc, char *argv[]) {

    int sd, size, val = 1;
    struct msg_st *sbufp;
    struct sockaddr_in raddr;
    if (argc < 2) {
        fprintf(stderr, "Usage....\n");
        exit(1);
    }
    if (strlen(argv[1]) > NAMEMAX) {
        fprintf(stderr, "Name is too long...\n");
        exit(1);
    }
    //取得socket
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    if (setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &val, sizeof (val)) < 0) {
        perror("setsockopt()");
        exit(1);
    }
    //bind()
    //发送消息
    size = sizeof (struct msg_st) + strlen(argv[1]);
    sbufp = malloc(size);
    if (sbufp == NULL) {
        perror("malloc()");
        exit(1);
    }
    strcpy(sbufp->name, argv[1]);
    sbufp->chinese = htonl(rand() % 100);
    sbufp->math = htonl(rand() % 100);
    raddr.sin_family = AF_INET;
    raddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET, "255.255.255.255", &raddr.sin_addr.s_addr);
    if (sendto(sd, sbufp, size, 0, (void *) &raddr, sizeof (raddr)) < 0) {
        perror("sendto()");
        exit(1);
    }

    free(sbufp);

    //关闭socket
    close(sd);

    exit(0);
}

4.5 多播/组播实例

proto头文件中添加内容

#define MTGROUP "224.2.2.2"

rcver接受端 加入多播组

int main() {
    int sd, size;
    struct sockaddr_in laddr, raddr;
    struct msg_st *rbufp;
    socklen_t raddr_len;
    char ipstr[IPSTRSIZE];

    size = sizeof (struct msg_st) + NAMEMAX - 1;
    rbufp = malloc(size);
    if (rbufp == NULL) {
        perror("malloc()");
        exit(1);
    }

    //1 取得socket用ipv4协议中默认支持报式传输的协议
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    //加入多播组
    struct ip_mreqn mreq;
    inet_pton(AF_INET, MTGROUP, &mreq.imr_multiaddr);
    inet_pton(AF_INET, "0.0.0.0", &mreq.imr_address);
    mreq.imr_ifindex = if_nametoindex("eth0");
    if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        perror("setsockopt()");
        exit(1);
    }
    //2 给socket绑定地址
    laddr.sin_family = AF_INET;
    laddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr.s_addr);
    if (bind(sd, (void *) &laddr, sizeof (laddr)) < 0) {
        perror("bind()");
        exit(1);
    }
    //3 接受信息
    raddr_len = sizeof (raddr); /* 注意初始化发送端的地址长度!!! */
    while (1) {
        recvfrom(sd, rbufp, size, 0, (void *) &raddr, &raddr_len);
        inet_ntop(AF_INET, &raddr.sin_addr.s_addr, ipstr, IPSTRSIZE);
        printf("---MSSAGE FROM %s:%d---\n", ipstr, ntohs(raddr.sin_port));
        printf("name = %s, math = %d, chinese = %d\n", rbufp->name, ntohl(rbufp->math), ntohl(rbufp->chinese));
    }
    //4 关闭socket
    close(sd);

    exit(0);
}

发送端snder 创建多播组

int main(int argc, char *argv[]) {

    int sd, size;
    struct msg_st *sbufp;
    struct sockaddr_in raddr;
    if (argc < 2) {
        fprintf(stderr, "Usage....\n");
        exit(1);
    }
    if (strlen(argv[1]) > NAMEMAX) {
        fprintf(stderr, "Name is too long...\n");
        exit(1);
    }
    //取得socket
    sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    //创建多播组
    struct ip_mreqn mreq;
    inet_pton(AF_INET, MTGROUP, &mreq.imr_multiaddr);
    inet_pton(AF_INET, "0.0.0.0", &mreq.imr_address);
    mreq.imr_ifindex = if_nametoindex("eth0");
    if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof (mreq)) < 0) {
        perror("setsockopt()");
        exit(1);
    }
    //bind()
    //发送消息
    size = sizeof (struct msg_st) + strlen(argv[1]);
    sbufp = malloc(size);
    if (sbufp == NULL) {
        perror("malloc()");
        exit(1);
    }
    strcpy(sbufp->name, argv[1]);
    sbufp->chinese = htonl(rand() % 100);
    sbufp->math = htonl(rand() % 100);
    raddr.sin_family = AF_INET;
    raddr.sin_port = htons(atoi(RCVPORT));
    inet_pton(AF_INET, MTGROUP, &raddr.sin_addr.s_addr);
    if (sendto(sd, sbufp, size, 0, (void *) &raddr, sizeof (raddr)) < 0) {
        perror("sendto()");
        exit(1);
    }

    free(sbufp);

    //关闭socket
    close(sd);

    exit(0);
}

5 流式套接字TCP

5.1 基本过程

客户端C端

  • 获取socket
  • 给socket取得地址
  • 发送连接请求
  • 收发消息
  • 关闭连接

服务端S端

  • 获取socket
  • 给socket取得地址
  • 将socket置为监听模式
  • 接受连接
  • 收发消息
  • 关闭连接

5.2 相关函数

listen() 监听一个socket

​ backlog原为半连接队列的大小,现将半连接队列取消后,该值代表全连接队列的大小。成功返回0,失败返回-1并设 置errno

int listen(int sockfd, int backlog);

accept() 在socket基础上建立一个连接

​ addr为对端的地址信息

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

send() 发送消息

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

connect() 建立连接

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

5.3 流式传输实例

proto协议头文件

#ifndef SOCKET_PROTO_H
#define SOCKET_PROTO_H

#define SERVERPORT "1999"

#define FMT_STAMP "%lld\r\n"

#endif //SOCKET_PROTO_H

client

int main(int argc, char *argv[]) {

    int sd;
    struct sockaddr_in raddr;
    FILE *fp;
    long long stamp;

    if (argc < 2) {
        fprintf(stderr, "Usage...\n");
        exit(1);
    }

    //1 取得socket
    sd = socket(AF_INET,SOCK_STREAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    //2 绑定端口bind()

    //3 发起连接
    raddr.sin_family = AF_INET;
    raddr.sin_port = htons(atoi(SERVERPORT));
    inet_pton(AF_INET, argv[1], &raddr.sin_addr);
    if (connect(sd, (void *) &raddr, sizeof (raddr)) < 0) {
        perror("connect()");
        exit(1);
    }
    //4 接受数据
    fp = fdopen(sd, "r+");
    if (fp == NULL) {
        perror("fdopen()");
        exit(1);
    }
    if (fscanf(fp, FMT_STAMP, &stamp) < 1) {
        fprintf(stderr, "Bad format!\n");
        exit(1);
    } else {
        fprintf(stdout, "stamp = %lld\n", stamp);
    }

    fclose(fp);

    exit(0);
}

server

#define IPSTRSIZE 40
#define BUFSIZE 1024

static void server_job(int sd) {
    int len;
    char buf[BUFSIZE];
    len = sprintf(buf, FMT_STAMP, (long long)time(NULL));
    if (send(sd, buf, len, 0) < 0) {
        perror("send()");
        exit(1);
    }
}

int main(int argc, char *argv[]) {

    int sd, newsd;
    struct sockaddr_in laddr, raddr;
    socklen_t rsize;
    char ipstr[IPSTRSIZE];
    pid_t pid;

    //1 取得socket
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    int val = 1;
    if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val)) < 0) {
        perror("setsickopt()");
        exit(1);
    }

    //2 绑定要监听的端口
    laddr.sin_family = AF_INET;
    laddr.sin_port = htons(atoi(SERVERPORT));
    inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);
    if (bind(sd, (void *) &laddr, sizeof (laddr)) < 0) {
        perror("bind()");
        exit(1);
    }

    //3 开始监听
    if (listen(sd, 200) < 0) {
        perror("listen()");
        exit(1);
    }

    while (1) {
        //4 接受连接
        rsize = sizeof(raddr);
        newsd = accept(sd, (void *) &raddr, &rsize);
        if (newsd < 0) {
            if (errno == EAGAIN || errno == EINTR) continue;
            perror("accept()");
            exit(1);
        }
        pid = fork();
        if (pid < 0) {
            perror("fork()");
            exit(1);
        }
        if (pid == 0) {
            close(sd);
            inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);
            printf("Client:%s:%d\n", ipstr, ntohs(raddr.sin_port));
            //5 发送数据
            server_job(newsd);
            close(newsd);
            exit(0);
        }
        close(newsd);
    }

    //6 关闭连接
    close(sd);
    exit(0);
}

​ 需要注意的是,上面的程序中父子进程都要关闭newsd,这样服务端和客户端的连接就全部关闭了,这时客户端的连 接也会自动关闭,此时会刷新fscanf的缓冲区才能读取到数据。若父子进程有一个newsd没有关闭,则服务端和客户 端的连接一直存在从而不能刷新fcanf的缓冲区导致客户端不能显示时间戳数据

服务端代码用静态进程池来实现

#define IPSTRSIZE 40
#define BUFSIZE 1024
#define PROCNUM 4

static void server_job(int sd) {
    int len;
    char buf[BUFSIZE];
    len = sprintf(buf, FMT_STAMP, (long long)time(NULL));
    if (send(sd, buf, len, 0) < 0) {
        perror("send()");
        exit(1);
    }
}

static void server_loop(int sd) {
    int newsd, rsize;
    struct sockaddr_in raddr;
    char ipstr[IPSTRSIZE];
    // 接受连接
    rsize = sizeof(raddr);
    while (1) {
        newsd = accept(sd, (void *) &raddr, &rsize);
        if (newsd < 0) {
            if (errno == EAGAIN || errno == EINTR) return;
            perror("accept()");
            exit(1);
        }
        
        inet_ntop(AF_INET, &raddr.sin_addr, ipstr, IPSTRSIZE);
        printf("Client:%s:%d\n", ipstr, ntohs(raddr.sin_port));
        //5 发送数据
        server_job(newsd);
        close(newsd);
        exit(0);
    }
}

int main(int argc, char *argv[]) {

    int sd, i;
    struct sockaddr_in laddr, raddr;
    socklen_t rsize;
    pid_t pid;

    //1 取得socket
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0) {
        perror("socket()");
        exit(1);
    }
    int val = 1;
    if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val)) < 0) {
        perror("setsickopt()");
        exit(1);
    }

    //2 绑定要监听的端口
    laddr.sin_family = AF_INET;
    laddr.sin_port = htons(atoi(SERVERPORT));
    inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);
    if (bind(sd, (void *) &laddr, sizeof (laddr)) < 0) {
        perror("bind()");
        exit(1);
    }

    //3 开始监听
    if (listen(sd, 200) < 0) {
        perror("listen()");
        exit(1);
    }
    
    for (i = 0; i < PROCNUM; i++) {
        pid = fork();
        if (pid < 0) {
            perror("fork()");
            exit(1);
        }
        if (pid == 0) {
            server_loop(sd);
            exit(0);
        }
    }
    
    for (i = 0; i < PROCNUM; i++) {
        wait(NULL);
    }

    close(sd);
    exit(0);
    
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/186958.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java8到Java17之间的主要特性描述

Java8到Java17之间的主要特性描述 文章目录Java8到Java17之间的主要特性描述Java8lambda表达式与Stream API方法引用&#xff08;Method Reference&#xff09;接口默认方法&#xff08;Default Methods&#xff09;类型注解&#xff08;Type Annotations&#xff09;可重复注解…

一文看懂YOLO v8

2023年&#xff0c;YOLO系列已经迭代到v8&#xff0c;v8与v5均出自U神&#xff0c;为了方便理解&#xff0c;我们将通过与v5对比来讲解v8。想了解v5的可以参考文章yolov5。 首先&#xff0c;回归一下yolov5&#xff1a; Backbone&#xff1a;CSPDarkNet结构&#xff0c;主要结…

结构体的内存对齐规则

结构体的内存 一、对齐规则 1.数据成员对齐规则:结构(struct或联合union&#xff09;的数据成员&#xff0c;第一个成员在与结构体变量偏移量为0的地址处&#xff0c;以后每个数据成员存储的起始位置要从该成员大小的整数倍开始&#xff08;比如int在32位机为4字节&#xff0…

anaconda/python安装虚拟环境并安装特定版本的库文件

anaconda/python安装虚拟环境并安装特定版本的库文件 文章目录anaconda/python安装虚拟环境并安装特定版本的库文件python安装虚拟环境安装教程pycharm加载虚拟环境以及安装指定的库文件python安装虚拟环境 安装教程 安装主要的代码指令就是下面这一句: conda create -n Env…

金融风控10

深度学习与金融风控 反欺诈生命周期 第一层设备与网络 - 代理检测 - IDC检测 - 模拟器/虚拟机检测 - 木马检测 第二层用户行为 - 注册行为 - 登录行为 - 交易行为 - 事件行为 - 时间间隔异常 第三层业务频次 - 注册频次 - 登录频次 - 交易频次 - 地域频次 - …

计算机组成原理笔记记录(第二章)

次为笔记记录&#xff0c;原视频链接为B站视频链接&#xff0c;若有错误请指出&#xff0c;看到就会改正 进制 r进制数及其转换成十进制数 r^n就是第n位的维权,n<0就是小数部分的位权。 例子:1011 为十进制的时候:10111103010211011100 为二进制的时候 1011123022121120(10…

Scipy误差函数详解

文章目录误差函数简介复平面上的误差函数与误差函数相关的函数误差函数简介 误差函数的实质是正态分布的概率&#xff0c;其重要性可见一斑&#xff0c;其表达式为 erf⁡2π∫0xe−t2dt\operatorname{erf}\frac{2}{\sqrt{\pi}}\int^x_0e^{-t^2}\text dt erfπ​2​∫0x​e−t2…

vue老项目增加提交格式化功能[eslint+prettier+husky+lint-staged]

一、当前项目情况说明 当前项目是已经开发迭代很久的项目&#xff0c;之前因为需求紧急&#xff0c;所以没有对代码格式话进行规范要求&#xff0c;导致每个开发人员提交的代码格式千差万别&#xff0c;增加了阅读难度及后期的维护成本&#xff0c;如果直接run lint&#xff0…

网络拓扑七大类型:总线、环形、星形、网状、树形、点对点、混合,我背的滚瓜烂熟!

大家好&#xff0c;这里是网络技术联盟站。 在网络世界中&#xff0c;经常会看到各种各样的网络拓扑&#xff0c;网络拓扑主要就是描述网络中各个元素的对应关系&#xff0c;那么网络中包含哪些类型的拓扑呢&#xff1f; 如上图所示&#xff0c;网络拓扑一般有两大类型&#x…

JS---数组的方法

一、方法 1.1、Pushing和Poping arr.push(1)&#xff1a;往arr数组的最后面压入1&#xff0c;push() 方法返回新数组的长度。 var fruits ["Banana", "Orange", "Apple", "Mango"]; fruits.push("Kiwi"); // fruits …

Ruoyi-Cloud框架学习-【04 用户登录】

前端 路由配置在router/index.js里 首页在views/index.vue4 前端端口与后台端口在vue.config.js里定义 vue.config.js 前台端口 后台端口 Ruoyi-Cloud登录流程 Login.vue 定义了登录handlerlogin&#xff0c;具体方法调用modules/user.js store/index.js 调用了modul…

【Stm32杂谈】:Stm32F103野火指南针开发板红外遥控程序问题记录和解析(个人理解)

项目场景&#xff1a; 最近在使用Stm32F103野火指南针开发板开发红外遥控外设得时候&#xff0c;用得是野火得开发板&#xff0c;本来发现应该很简单的事情&#xff0c;官方也很贴切的提供了官方例程。但是居然有问题&#xff0c;无法正常使用。 于是这篇文章应运而生&#xff…

环保数采仪 5G无线环保数采仪 智能环保数采仪

计讯物联智能环保数采仪&#xff0c;无线远距离数据传输、采集、控制、存储。支持全网通5G/4G移动网络、北斗、有线通信&#xff0c;数据上报云监控中心&#xff0c;支持GPS定位分散设备远程统一管理。支持环保协议&#xff0c;对接各省市县级监管平台&#xff0c;广泛应用于废…

Kubernetes集群搭建

Kubernetes集群搭建 目录 前言前期准备K8S集群安装 虚拟机设置安装K8S集群k8s部署Nginx 附录1 Docker安装附录2 yum k8s 问题附录3 k8s start问题附录4 k8s master init附录5 node节点添加进集群失败&#xff0c;可以删除节点重新添加 前言 本文指定Docker与K8s版本&#xf…

DynaSLAM-3 DynaSLAM中Mask R-CNN部分源码解析(Ⅱ)

目录 1.FPN 1.1 FPN层原理 1.2 FPN代码解析 2. 候选框的生成 2.1 根据特征图生成候选框 1.FPN 1.1 FPN层原理 在Faster R-CNN网络中&#xff0c;提取特征的时候&#xff0c;将原始数据经过一系列的卷积层&#xff0c;我们只用最后一层的特征图进行提取。 比如五层卷积神经…

C++(36)-VS2019- 动态库调用

1.被调用的动态库 MyDll 2.调用的可执行文件 MyExe 源码实例链接&#xff1a;MFC-VS2019-EXE调用DLL-demo.zip-C代码类资源-CSDN下载 1.MyDll 1.1 MyDll头文件&#xff1a;MyDll.h 声明此动态库为导出动态库。 声明导出函数。 #pragma once#define MYDECLARE_PUB…

【05】FreeRTOS的中断管理

目录 1.什么是中断 2.中断优先级分组 2.1中断优先级分组-介绍 2.2中断优先级分组-配置 2.3中断优先级分组-特点 3.中断相关寄存器 3.1寄存器地址 3.2在FreeRTOS中配置PendSV和Systick中断优先级 3.3中断相关寄存器 4.FreeRTOS中断管理实验 4.1修改freertos_demo.c …

2023.1.30作业-【尝试移植TF-A】

1、解压源码&#xff0c;进入目录如图一 2、解压源码包 3、进入解压后的目录&#xff0c;打入官方补丁 4、查看SD卡的分区&#xff0c;发现正常无需重新分区 5、导入编译工具查看是否正常导入 6、添加设备树等相关文件 7、修改上层目录下的 Makefile.sdk中添加 stm32mp157a-fsm…

chatGPT模型简介

ChatGPT的工作原理 chatGPT 是一款由 OpenAI 开发的聊天机器人模型&#xff0c;它能够模拟人类的语言行为&#xff0c;与用户进行自然的交互。它的名称来源于它所使用的技术—— GPT-3架构&#xff0c;即生成式语言模型的第3代。 chatGPT的核心技术是 GPT-3 架构。它通过使用大…

vue 自动生成swagger接口请求文件

前端: vue-element-admin 后端: .net core (6.0) 找了很多自动生成的代码的&#xff0c;感觉不太行&#xff0c;可能是我不太懂。所以自己根据swagger.json去生成了js请求文件。 后端很简单&#xff0c;就不说了&#xff0c;只要能访问到swagger的地址就可以&#xff0c;主要…