【lesson62】网络通信UdpSocket版

news2024/10/4 14:56:08

文章目录

  • UdpSocket
  • UdpServer.hpp
    • UdpServer类
      • 成员变量解释
      • 成员函数解释
    • UdpServer的实现
    • ServerIinit的实现
      • socket
      • bind
      • htons
      • inet_addr
      • 具体实现
    • ServerStart的实现
      • recvfrom
      • sendto
      • ntohs
      • inet_ntoa
      • 具体实现
    • ~UdpServer函数实现
    • UdpServer.hpp整体完整代码
  • UdpServer.cc
  • UdpClient.cc
    • Thread.hpp
    • UdpClient.cc实现
  • Common.h
  • Log.hpp

UdpSocket

我们要用udp协议来实现网络通信。
我们要用udp协议实现两样:
UdpServer(服务器)
UdpClient(客户端)

客服端可以向服务器发送一些数据或者请求,服务器对其进行响应

UdpServer.hpp

UdpServer类

class UdpServer
{
public:
    UdpServer(uint16_t port, std::string ip = "")
        : _port(port),
          _ip(ip)
    {}

    bool ServerIinit()
    {}

    void ServerStart()
    {}

    ~UdpServer()
    {}

private:
    uint16_t _port;
    std::string _ip;
    int _sock;

    std::unordered_map<std::string, struct sockaddr_in> _users;
};

成员变量解释

uint16_t _port;
std::string _ip;
int _sock;
std::unordered_map<std::string, struct sockaddr_in> _users;

_port:服务器进程要绑定的端口号
_ip:指定连接该服务器的客户端IP,可以设为INADDR_ANY支持任意客户端连接服务器
_sock:套接字
_users:存储所有连接该服务器的端口号和sockaddr_in

成员函数解释

UdpServer(uint16_t port, std::string ip = "")
    : _port(port),
      _ip(ip)
{}

bool ServerIinit()
{}

void ServerStart()
{}

~UdpServer()
{}

UdpServer:构造函数
参数解释:
port:服务器要绑定的端口号
ip:服务器要绑定的IP地址,如果不传默认为缺省值“”,如果为缺省值我们可以设为INADDR_ANY支持任意IP绑定

ServerIinit:初始化服务器

ServerStart:启动服务器

~UdpServer:析构函数,释放一些资源

UdpServer的实现

UdpServer(uint16_t port, std::string ip = "")
    : _port(port),
      _ip(ip)
{}

ServerIinit的实现

需要用到的接口介绍

socket

在这里插入图片描述
参数解释:
domain:
在这里插入图片描述
type:
在这里插入图片描述
protocol:
在这里插入图片描述
return value:
在这里插入图片描述
在这里插入图片描述

bind

在这里插入图片描述
在这里插入图片描述
参数介绍:
socetfd:创建套接字文件的文件描述符
addr:表示struct sockaddr的地址,用于设定要绑定的ip和端口
addr_len:struct sockaddr结构体的大小

struct sockaddr {
   sa_family_t sa_family;
   char        sa_data[14];
}

sa_family 用于指定AF_***表示使用什么协议族的ip
sa_data 存放ip和端口
这里有一个问题,直接向sa_data中写入ip和端口号有点麻烦,内核提供struct sockaddr_in结构体进行写入,通过/usr/include/linux/in.h可以看到结构体原型
使用该结构体时需要包含<netinet/in.h>头文件,且sockaddr_in结构体是专门为tcp/ip协议族使用,其他协议族需要使用其对应的转换结构体,比如**“域通信协议族**” 使用的是sockaddr_un结构体

struct sockaddr_in {
	  __kernel_sa_family_t  sin_family;     /* Address family               */
	  __be16                sin_port;       /* Port number                  */
	  struct in_addr        sin_addr;       /* Internet address             */
	
	  /* Pad to size of `struct sockaddr'. 设置IP端口号这个成员暂时用不到 */
	  unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
	                        sizeof(unsigned short int) - sizeof(struct in_addr)];
};

/* Internet address.填补相比于struct sockaddr所缺的字节数,保障强制转换不要出错 */
struct in_addr {
        __be32  s_addr; // __be32是32位的unsigned int ,因为ipv4是无符号32位整型 
};

sockaddr_in结构体中存放的端口和ip是分开的,使用struct sockaddr_in设置后,让后将其强制转换struct sockaddr类型,然后传递给bind函数即可

htons

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

inet_addr

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

具体实现

bool ServerIinit()
{
	//1.创建套接字
	//AF_INET 表示是网络编程
	//SOCK_DGRAM 表示使用的是udp协议
    _sock = socket(AF_INET, SOCK_DGRAM, 0);
    //如果返回值小于0,说明创建套接字失败
    if (_sock < 0)
    {
    	//打出创建的日志信息
        LogMessage(FATAL, "socket %s", strerror(errno));
        exit(2);
    }
    //打出创建的日志信息
    LogMessage(NORMAL, "udp socket success");
	
	//定义sockaddr_in 对象
    struct sockaddr_in local;
    //初始化sockaddr_in ,初始化为0
    bzero(&local, sizeof(local));
	
	//向sockaddr_in对象 local填入一些数据
	//local.sin_port server要绑定的端口号
	//local.sin_family server使用的协议家族,指明要使用什么协议
	//local.sin_addr.s_addr server要绑定的IP地址
	//htons()将端口号转化为大端
    local.sin_port = htons(_port);
    local.sin_family = AF_INET;
    
    //判断要绑定的IP地址是否为空,如果为空填入INADDR_ANY表示绑定任意IP地址
    //如果不为空填入该IP
    //inet_addr()做了两个工作
    //1.将字符串IP转化为32位整数 2.将32位整数转化为大端
    local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

	//2.开始绑定
    int n = bind(_sock, (struct sockaddr *)&local, sizeof(local));
    //如果绑定失败n bind会返回-1
    if (n == -1)
    {
    	//打印出绑定的日志信息
        LogMessage(FATAL, "bind %s", strerror(errno));
        exit(3);
    }
    //打印出绑定的日志信息
    LogMessage(NORMAL, "udp bind success");
	
	//到最后成功打印出初始化成功的日志信息
    LogMessage(NORMAL, "init udp server done ... %s", strerror(errno));
    return true;
}

ServerStart的实现

需要用到的接口介绍

recvfrom

在这里插入图片描述
在这里插入图片描述
参数解释:
sockfd:创建套接字文件的文件描述符
buffer:输出型参数,数据缓冲区数组,会把从网络中获取到的数据放入其中
len:buffer的大小
flages
在这里插入图片描述
src_addr:指向一个sockaddr结构体,用于存储发送方的地址信息。
addrlen:src_addr结构体的大小
return value:
在这里插入图片描述
在这里插入图片描述

sendto

在这里插入图片描述

在这里插入图片描述
参数解释:
sockfd:创建套接字文件的文件描述符
buffer:要输入数据的数组
len:输入数据的长度
dest_addr:指向一个sockaddr结构体,用于存储接受方的地址信息。
addrlen:dest_addr结构体的大小
flags:
在这里插入图片描述
return value:
在这里插入图片描述
在这里插入图片描述

ntohs

在这里插入图片描述

inet_ntoa

在这里插入图片描述
在这里插入图片描述

具体实现

void ServerStart()
{
	//数据缓冲区
    char buffer[BUFFER_SIZE];
    //客户端的IP和port的临时存放区
    char key[64];
	
	//服务器肯定是一直循环执行的
    while (true)
    {
    	//定义peer结构体,peer是输出型参数,可以获取客户端的IP和port
        struct sockaddr_in peer;
        //计算peer结构体的大小
        socklen_t len = sizeof(peer);
        //初始化peer结构体,初始化为0
        memset(&peer, 0, len);
        //recvfrom从_sock文件中获取数据
        int s = recvfrom(_sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&peer, &len);
		
		//s > 0 代表成功获取数据,我们要对该数据进行处理
        if (s > 0)
        {
            buffer[s] = '\0';
			
			//因为端口是从网络中来的,所以是大端序列
			//ntohs将大端的port转化为小端
            uint16_t src_port = ntohs(peer.sin_port);
            
            //inet_ntoa做了两个工作
            //1.将网络中获取到的32位整数IP地址转化为小端序列
            //2.将IP地址转化为字符串
            std::string src_ip = inet_ntoa(peer.sin_addr);
			
			//处理获取到的数据
            printf("[%s:%d]# %s\n", src_ip.c_str(), src_port, buffer);
            //将网络中的IP地址和端口号存入key中
            snprintf(key, sizeof(key), "%s-%u", src_ip.c_str(), src_port);
            LogMessage(NORMAL, "key: %s", key);
			
			//在_users中查找key,如果存在说明这个客户端之前有连接果不用在添加进_user中
            auto ret = _users.find(key);
            //如果不存在如果存在说明这个客户端第一次连接服务器,将其添加进_user中
            if (ret == _users.end())
            {
                LogMessage(NORMAL, "add new user : %s", key);
                _users.insert(std::make_pair(key, peer));
            }
        }
		
		//将收到的消息广播给所有主机
        for (auto &iter : _users)
        {
            std::string send_message(key);
            send_message += "# ";
            send_message += buffer;
            LogMessage(NORMAL, "push message to %s", iter.first.c_str());
            //std::cout << send_message << std::endl;
            //sendto发送数据到_sock文件中,并指明要发送主机的IP地址和端口号
            //主机的IP地址和端口号在(struct sockaddr *)&iter.second
            sendto(_sock, send_message.c_str(), send_message.size(), 0,
                   (struct sockaddr *)&iter.second, len);
        }
    }
}

~UdpServer函数实现

~UdpServer()
    {
        if (_sock >= 0)
        {
            close(_sock);
        }
    }

UdpServer.hpp整体完整代码

#include "Common.h"
#include "Log.hpp"

class UdpServer
{
public:
    UdpServer(uint16_t port, std::string ip = "")
        : _port(port),
          _ip(ip)
    {
    }

    bool ServerIinit()
    {
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock < 0)
        {
            LogMessage(FATAL, "socket %s", strerror(errno));
            exit(2);
        }
        LogMessage(NORMAL, "udp socket success");

        struct sockaddr_in local;
        bzero(&local, sizeof(local));

        local.sin_port = htons(_port);
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

        int n = bind(_sock, (struct sockaddr *)&local, sizeof(local));
        if (n == -1)
        {
            LogMessage(FATAL, "bind %s", strerror(errno));
            exit(3);
        }
        LogMessage(NORMAL, "udp bind success");

        LogMessage(NORMAL, "init udp server done ... %s", strerror(errno));
        return true;
    }

    void ServerStart()
    {
        char buffer[BUFFER_SIZE];
        char key[64];

        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            memset(&peer, 0, len);
            int s = recvfrom(_sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&peer, &len);

            if (s > 0)
            {
                buffer[s] = '\0';

                uint16_t src_port = ntohs(peer.sin_port);
                std::string src_ip = inet_ntoa(peer.sin_addr);

                printf("[%s:%d]# %s\n", src_ip.c_str(), src_port, buffer);
                snprintf(key, sizeof(key), "%s-%u", src_ip.c_str(), src_port);
                LogMessage(NORMAL, "key: %s", key);

                auto ret = _users.find(key);
                if (ret == _users.end())
                {
                    LogMessage(NORMAL, "add new user : %s", key);
                    _users.insert(std::make_pair(key, peer));
                }
            }

            for (auto &iter : _users)
            {
                std::string send_message(key);
                send_message += "# ";
                send_message += buffer;
                LogMessage(NORMAL, "push message to %s", iter.first.c_str());
                //std::cout << send_message << std::endl;
                sendto(_sock, send_message.c_str(), send_message.size(), 0,
                       (struct sockaddr *)&iter.second, len);
            }
        }
    }

    ~UdpServer()
    {
        if (_sock >= 0)
        {
            close(_sock);
        }
    }

private:
    uint16_t _port;
    std::string _ip;
    int _sock;

    std::unordered_map<std::string, struct sockaddr_in> _users;
};

UdpServer.cc

#include "udp_server.hpp"

static void Usage(std::string proc)
{
    std::cout << "Usage:\t\n " << proc << " port\n" << std::endl;
}

int main(int argc,char* argv[])
{
	//使用规则必须是 ./server port
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    uint16_t port = atoi(argv[1]);
    //使用智能指针管理UdpServer
    std::unique_ptr<UdpServer> svr(new UdpServer(port));

    svr->ServerIinit();
    svr->ServerStart();

    return 0;
}

UdpClient.cc

Thread.hpp

#include "Common.h"
#include "Log.hpp"

typedef void *(*fun_t)(void *);

class ThreadData
{
public:
    std::string _name;
    void *_args;
};

class Thread
{
public:
    Thread(std::string name, fun_t routine, void *args)
    {
        _thread_data._name = name;
        _func = routine;
        _thread_data._args = args;
    }

    void Start()
    {
        pthread_create(&_tid, nullptr, _func, (void*)&_thread_data);
        //std::cout <<  _thread_data._name << " create success" << std::endl;
        LogMessage(NORMAL,"%s creadte success",_thread_data._name.c_str());
    }

    void Join()
    {
        pthread_join(_tid, nullptr);
        //std::cout <<  _thread_data._name << " join success" << std::endl;
        LogMessage(NORMAL,"%s join success",_thread_data._name.c_str());
    }

    std::string GetName()
    {
        return _thread_data._name;
    }

private:
    ThreadData _thread_data;
    pthread_t _tid;
    fun_t _func;
};

UdpClient.cc实现

#include "Common.h"
#include "Log.hpp"
#include "Thread.hpp"

std::string serverip;
uint16_t serverport = 0;

static void Usage(std::string proc)
{
    std::cout << "Usage:\t\n " << proc << " serverip serverport\n"
              << std::endl;
}

//发送数据的线程
void *udpSend(void *args)
{
    int sock = *((int *)((ThreadData *)args)->_args);

    //std::cout << sock << std::endl;

    struct sockaddr_in server;
    bzero(&server, sizeof(server));

    server.sin_port = htons(serverport);
    //std::cout << serverport << std::endl;;
    //std::cout << serverip << std::endl;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    std::string message;
    while (true)
    {
        std::cerr << "Please Entery your message: ";
        std::getline(std::cin, message);
        if (message.c_str() == "quit")
        {
            LogMessage(NORMAL, "client quit");
            break;
        }

        sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));
    }
}

//接收数据的线程
void *udpRecv(void *args)
{
    int sock = *((int *)((ThreadData *)args)->_args);
    //std::cout << sock << std::endl;
    char buffer[BUFFER_SIZE];
    while (true)
    {
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        int s = recvfrom(sock,buffer,sizeof(buffer),0,(struct sockaddr*)&temp,&len);

        //std::cout << buffer;
        if(s > 0)
        {
            buffer[s] = '\0';
            std::cout << buffer << std::endl;
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        LogMessage(FATAL, "socket %s", strerror(errno));
        exit(1);
    }
    LogMessage(NORMAL, "socket %s", strerror(errno));

    serverip = argv[1];
    serverport = atoi(argv[2]);
	
	//多线程版
    std::unique_ptr<Thread> sender(new Thread("send_thread", udpSend, (void *)&sock));
    std::unique_ptr<Thread> recver(new Thread("recv_thread", udpRecv, (void *)&sock));

    sender->Start();
    recver->Start();

    sender->Join();
    recver->Join();

    // LogMessage(NORMAL, "%s%d",serverip.c_str(),serverport);
	
	//单线程版 弊端:一直卡在发送数据处,当别人发消息时,无法及时接收
    /* struct sockaddr_in server;
    bzero(&server, sizeof(server));

    server.sin_port = htons(serverport);
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    std::string message;
    char buffer[BUFFER_SIZE];
    while (true)
    {
        std::cout << "Please Entery your message: ";
        std::getline(std::cin, message);
        if (message.c_str() == "quit")
        {
            LogMessage(NORMAL, "client quit");
            break;
        }

        //std::cout << message;
        sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));

        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        int s = recvfrom(sock,buffer,sizeof(buffer),0,(struct sockaddr*)&temp,&len);

        //std::cout << buffer;
        if(s > 0)
        {
            buffer[s] = '\0';
            std::cout << buffer << std::endl;
        }
    } */
    return 0;
}

Common.h

共用的头文件

#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdarg.h>
#include <pthread.h>

#define BUFFER_SIZE 1024

Log.hpp

打印日志的函数

#pragma once
#include "Common.h"

// 日志是有日志级别的
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4

#define STANDARD_NUM 1024
#define CUSTOM_NUM 1024

const char *gLevelMap[] = {
    "DEBUG",
    "NORMAL",
    "WARNING",
    "ERROR",
    "FATAL"};

void LogMessage(int level, const char *format, ...)
{
 #ifndef DEBUG_SHOW
    if(level== DEBUG) return;
#endif
    // 标准部分
    char standard_buffer[STANDARD_NUM];
    snprintf(standard_buffer, sizeof(standard_buffer), "[%s][%ld]", gLevelMap[level], time(nullptr));

    // 自定义部分
    char custom_buffer[CUSTOM_NUM];
    va_list args;
    va_start(args, format);
    vsnprintf(custom_buffer, sizeof(custom_buffer), format, args);
    va_end(args);

    printf("%s%s\n", standard_buffer, custom_buffer);
}

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

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

相关文章

Java学习--黑马SpringBoot3课程个人总结-2024-02-12

1.环境准备 出现报错 Vue 引入路径正确的&#xff0c;但一直报错&#xff1a; Already included file name ‘‘ differs from file name ‘‘ only in casing. 解决方案来自此链接 2.注册界面的搭建 代码如下 <script setup> import { User, Lock } from element-plus/…

【C语言】通讯录(静态版本+动态版本)思路解析+完整源代码

通讯录 由于代码比较长&#xff0c;为了增加可读性&#xff0c;分成了contact.h&#xff0c;contact.c&#xff0c;test.c&#xff0c;分别用来声明函数或者类型&#xff0c;实现函数功能&#xff0c;测试代码 contact.h 我们希望通讯录具有增加联系人&#xff0c;删除联系人…

防火墙之firewalld基础

一、firewalld的简介 firewalld防火墙是Centos7系统默认的防火墙管理工具&#xff0c;取代了之前的iptables防火墙&#xff0c;也是工作在网络层&#xff0c;属于包过滤防火墙。 firewalld和iptables都是用来管理防火墙的工具&#xff08;属于用户态&#xff09;来定义防火墙的…

css pointer-events 多层鼠标点击事件

threejs 无法滑动视角&#xff0c;菜单界面覆盖threejs操作事件。 pointer-events /* Keyword values */ pointer-events: auto; pointer-events: none; pointer-events: visiblePainted; /* SVG only */ pointer-events: visibleFill; /* SVG only */ pointer-events: visib…

web基础及http协议 (二) apache

一、httpd 安装组成 http 服务基于 C/S 结构 1 .常见http 服务器程序 httpd apache&#xff0c;存在C10K&#xff08;10K connections&#xff09;问题 nginx 解决C10K问题lighttpd IIS .asp 应用程序服务器 tomcat .jsp 应用程序服务器 jetty 开源的servlet容器&#xf…

Linux 驱动开发基础知识——LED 模板驱动程序的改造:设备树(十一)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

探索线性回归中的梯度下降法

目录 前言1 梯度下降的基本思想2 梯度下降的公式3 梯度下降的步骤3.1 初始化参数3.2 计算梯度3.3 更新参数3.4 迭代更新 4 学习率的控制4.1 过大学习率的问题4.2 过小学习率的问题4.3 学习率的调整 5 批量梯度下降方法5.1 批量梯度下降&#xff08;Batch Gradient Descent&…

代码随想录算法训练营DAY20 | 二叉树(7) (续)

一、LeetCode 236 二叉树的最近公共祖先 题目链接&#xff1a;236.二叉树的最近公共祖先https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/ 思路&#xff1a;利用后序遍历是天然回溯过程、方便实现自底向上查找的原理&#xff0c;递归寻找公…

基于SpringBoot的高校竞赛管理系统

基于SpringBoot的高校竞赛管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 个人中心 管理员界面 老师界面 摘要 高校竞赛管理系统是为了有效管理学校…

书生开源大模型-第2讲-笔记

1.环境准备 1.1环境 先克隆我们的环境 bash /root/share/install_conda_env_internlm_base.sh internlm-demo1.2 模型参数 下载或者复制下来&#xff0c;开发机中已经有一份参数了 mkdir -p /root/model/Shanghai_AI_Laboratory cp -r /root/share/temp/model_repos/inter…

分库分表浅析

简介 对于任何系统而言&#xff0c;都会设计到数据库随着时间增长而累积越来越多的数据&#xff0c;系统也因为越来越多的需求变迁导致原有的设计不再满足现状&#xff0c;为了解决这些问题&#xff0c;分库分表就会走进视野&#xff0c;带着几个问题走入分库分表。 什么是分…

嵌入式学习第十八天(目录IO)

目录IO: 1. mkdir int mkdir(const char *pathname, mode_t mode); 功能&#xff1a;创建目录文件 参数&#xff1a; pathname&#xff1a;文件路径 mode&#xff1a;文件的权限 rwx rwx rwx 111 111 111 0 7 7 7 r&#xff1a;目录中是否能够查看文件 w&#xff1a;目…

瑞_23种设计模式_代理模式

文章目录 1 代理模式&#xff08;Proxy Pattern&#xff09;1.1 介绍1.2 概述1.3 代理模式的结构 2 静态代理2.1 介绍2.2 案例——静态代理2.3 代码实现 3 JDK动态代理★★★3.1 介绍3.2 代码实现3.3 解析代理类3.3.1 思考3.3.2 使用 Arthas 解析代理类3.3.3 结论 3.4 动态代理…

ARM体系在linux中的中断抢占

上一篇说到系统调用等异常通过向量el1_sync做处理&#xff0c;中断通过向量el1_irq做处理&#xff0c;然后gic的工作都是为中断处理服务&#xff0c;在rtos中&#xff0c;我们一般都会有中断嵌套和优先级反转的概念&#xff0c;但是在linux中&#xff0c;中断是否会被其他中断抢…

RTC时钟

目录 一、STM32F407内部RTC硬件框图&#xff0c;主要由五大部分组成&#xff1a; 二、硬件相关引脚 三、具体代码设置步骤 四、了解其它知识点 一、STM32F407内部RTC硬件框图&#xff0c;主要由五大部分组成&#xff1a; ① 时钟源 (1)LSE&#xff1a;一般我们选择 LSE&am…

网络编程_TCP通信综合练习:

1 //client&#xff1a;&#xff1a; public class Client {public static void main(String[] args) throws IOException {//多次发送数据//创建socket对象,填写服务器的ip以及端口Socket snew Socket("127.0.0.1",10000);//获取输出流OutputStream op s.getOutput…

python统计分析——一元线性回归分析

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 import matplotlib.pyplot as plt import seaborn as sns sns.set() # 用于估计统计…

【高效开发工具系列】PyCharm使用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

vue3项目配置按需自动导入API组件unplugin-auto-import

场景应用&#xff1a;避免写一大堆的import&#xff0c;比如关于Vue和Vue Router的 1、安装unplugin-auto-import npm i -D unplugin-auto-import 2、配置vite.config import AutoImport from unplugin-auto-import/vite//按需自动加载API插件 AutoImport({ imports: ["…

Unity中的Lerp插值的使用

Unity中的Lerp插值使用 前言Lerp是什么如何使用Lerp 前言 平时在做项目中插值的使用避免不了&#xff0c;之前一直在插值中使用存在误区&#xff0c;在这里浅浅记录一下。之前看的博客或者教程还多都存在一个“永远到达不了&#xff0c;只能无限接近”的一个概念。可能是之前脑…