【Linux】Socket编程—UDP


文章目录
- 1.Echo server
- 2. Dict server
- 3. ChatServer
1.Echo server
简单的回显服务器和客户端代码。
- 服务器代码:
#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <cerrno>
#include <strings.h>#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "Log.hpp"
#include "InetAddr.hpp"
#include "Common.hpp"using namespace LogModule;
using namespace InetAddrModule;const static int gsockfd = -1;
const static uint16_t gdefaultport = 8080;class UdpServer
{
public:UdpServer(uint16_t port = gdefaultport): _sockfd(gsockfd),_addr(port),_isrunning(false){}void InitServer(){// 1. 创建socket_sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(LogLevel::FATAL) << "socket: " << strerror(errno);Die(SOCKET_ERR);}LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;// 2. bind : 设置进入内核中int n = ::bind(_sockfd, _addr.NetAddr(), _addr.NetAddrLen());if (n < 0){LOG(LogLevel::FATAL) << "bind: " << strerror(errno);Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";}bool Start(){_isrunning = true;while (true){char inbuffer[1024]; // stringstruct sockaddr_in peer;socklen_t len = sizeof(peer); // 必须设定ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer)-1, 0, CONV(&peer),&len);if(n > 0){inbuffer[n] = 0;InetAddr client(peer);//获取cilent相关信息std::string cilentmessage = client.Ip()+":"+std::to_string(client.Port())+"# "+ inbuffer;LOG(LogLevel::DEBUG)<<cilentmessage;//将获取到的信息写回clientstd::string echo_string = "echo# ";echo_string += inbuffer;::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,client.NetAddr(),client.NetAddrLen());}}_isrunning = false;}~UdpServer(){if (_sockfd > gsockfd)::close(_sockfd);}private:InetAddr _addr; // 服务器地址包括ip和portint _sockfd;bool _isrunning; // 服务器运行状态
};#endif
要使用网络服务器需要使用socket创建套接字,然后将IP和端口号bind进入内核,最后就可以调用recv/sendto接口进行网络发送和接收信息了
服务器使用代码:
#include "UdpServer.hpp"// ./server_udp localport
int main(int argc, char *argv[])
{ENABLE_CONSOLE_LOG_STRATEGY();std::unique_ptr<UdpServer> svr_uptr;if (argc == 2){uint16_t port = std::stoi(argv[1]);svr_uptr = std::make_unique<UdpServer>(port);}elsesvr_uptr = std::make_unique<UdpServer>();svr_uptr->InitServer();svr_uptr->Start();return 0;
}
服务器需要输入端口号,不输入也行,服务器默认端口号为8080
- 客户端代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"using namespace LogModule;
using namespace InetAddrModule;int sockfd = -1;//./udp_client server_ip server_port
int main(int argc, char *argv[])
{if(argc!=3){LOG(LogLevel::ERROR)<<"Usage:" << argv[0] << " serverip serverport" ;Die(ARGV_ERR);}//1.创建sockfdsockfd = ::socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){LOG(LogLevel::WARNING)<<"client sockfd fail...";Die(SOCKET_ERR);} LOG(LogLevel::INFO)<<"client sockfd success...";//2.填充服务器信息std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);InetAddr ServerAddr(serverip,serverport);//3.发送请求给服务器while(true){//3.1获取信息std::cout << "Please Enter# ";std::string message;std::getline(std::cin, message);//3.2发送信息给服务器ssize_t n = ::sendto(sockfd,message.c_str(),sizeof(message),0,ServerAddr.NetAddr(),ServerAddr.NetAddrLen());if(n < 0){LOG(LogLevel::ERROR)<<"client sendto fail...";continue;}//3.3从服务器接收信息char buffer[1024];struct sockaddr_in tmp;socklen_t len = sizeof(tmp);ssize_t m = ::recvfrom(sockfd,buffer,sizeof(buffer)-1,0,CONV(&tmp),&len);if(m > 0){buffer[m] = 0;std::cout<<buffer<<std::endl;}else{LOG(LogLevel::ERROR)<<"client recvfrom fail...";}}return 0;
}
同样,客户端要进行网络通信也需要创建套接字,但是不需要bind信息进入内核,因为在接收到网络信息时会自动进行bind
客户端需要输入服务器IP地址和端口号port
- 网络地址类:
因为在进行网络通信时不可避免的需要频繁使用到相关信息,所以我们可以考虑将它们封装成为一个类,设置一些常用的方法
#pragma once#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"namespace InetAddrModule
{class InetAddr{private:void PortNet2Host() // port网络转主机{_port = ::ntohs(_net_addr.sin_port);}void IpNet2Host() // IP网络转主机{char ipbuffer[64];const char *ip = ::inet_ntop(AF_INET, &_net_addr.sin_addr, ipbuffer, sizeof(ipbuffer));_ip = ip;}public:InetAddr(){}InetAddr(const struct sockaddr_in &addr) : _net_addr(addr) // 获取传来的sockaddr的ip和port{PortNet2Host();IpNet2Host();}InetAddr(uint16_t port) : _port(port), _ip(""){_net_addr.sin_family = AF_INET;_net_addr.sin_port = htons(_port);//主机转网络_net_addr.sin_addr.s_addr = INADDR_ANY;//表示可以介绍任何ip地址}InetAddr(const std::string& ip,uint16_t port) : _port(port), _ip(ip){_net_addr.sin_family = AF_INET;_net_addr.sin_port = htons(_port);//主机转网络_net_addr.sin_addr.s_addr = ::inet_addr(ip.c_str());}struct sockaddr *NetAddr() { return CONV(&_net_addr); }socklen_t NetAddrLen() { return sizeof(_net_addr); }std::string Ip() { return _ip; }uint16_t Port() { return _port; }~InetAddr(){}private:struct sockaddr_in _net_addr;std::string _ip;uint16_t _port;};
}
因为各种机器之间不兼容等例如大端/小端模式,所以在实际进行网络通信时我们需要将发送的ip地址和端口号从主机模式转换为网络模式。
在网络编程中,当一个进程需要绑定一个网络端口以进行通信时,可以使用INADDR_ANY 作为 IP 地址参数。这样做意味着该端口可以接受来自任何 IP 地址的连接请求,无论是本地主机还是远程主机。例如,如果服务器有多个网卡(每个网卡上有不同的 IP 地址),使用 INADDR_ANY 可以省去确定数据是从服务器上具体哪个网卡/IP 地址上面获取的。
结果如下:
2. Dict server
上述echo server仅仅是将收到的消息回显给客户端,其实我们还可以在服务器中加一点业务处理,比如翻译功能。
所以我们可以创建一个Dictionary
类,将翻译词典封装起来:
Dict.txt:
apple: 苹果
banana: 香蕉
cat: 猫
dog: 狗
book: 书
pen: 笔
happy: 快乐的
sad: 悲伤的
run: 跑
jump: 跳
teacher: 老师
student: 学生
car: 汽车
bus: 公交车
love: 爱
hate: 恨
hello: 你好
goodbye: 再见
summer: 夏天
winter: 冬天
Dict.hpp:
#pragma once#include <iostream>
#include <fstream>
#include <unordered_map>
#include "Log.hpp"namespace DictionaryModule
{const std::string sep = ": "; // 分割符using namespace LogModule;class Dict{private://将词典内容从Dict.txt中加载进来void DownloadDict(){std::ifstream in(_dictpath);if (!in.is_open()){LOG(LogLevel::WARNING) << "DownloadDict fail...";return;}std::string line;while (getline(in, line)){if (line.empty())continue;// 加入词典size_t pos = line.find(sep);_dict.insert({line.substr(0, pos), line.substr(pos + sep.size())});}}public:Dict(const std::string &dictpath = "./Dict.txt") : _dictpath(dictpath){DownloadDict(); // 加载词典}std::string Translate(const std::string &key){auto iter = _dict.find(key);if (iter == _dict.end())return std::string("Unknown");elsereturn iter->second;}~Dict(){}private:std::string _dictpath;std::unordered_map<std::string, std::string> _dict;};
}
有了翻译的功能后,我们就可以将其嵌入服务器内部使用,所以我们在UdpServer
类成员中添加一个回调方法,并在Start
函数中使用:
#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <cerrno>
#include <strings.h>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "Log.hpp"
#include "InetAddr.hpp"
#include "Common.hpp"using namespace LogModule;
using namespace InetAddrModule;using func_t = std::function<std::string(const std::string&)>;
const static int gsockfd = -1;
const static uint16_t gdefaultport = 8080;class UdpServer
{
public:UdpServer(func_t func,uint16_t port = gdefaultport): _sockfd(gsockfd),_addr(port),_isrunning(false),_func(func){}void InitServer(){// 1. 创建socket_sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(LogLevel::FATAL) << "socket: " << strerror(errno);Die(SOCKET_ERR);}LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;// 2. bind : 设置进入内核中int n = ::bind(_sockfd, _addr.NetAddr(), _addr.NetAddrLen());if (n < 0){LOG(LogLevel::FATAL) << "bind: " << strerror(errno);Die(BIND_ERR);}LOG(LogLevel::INFO) << "bind success";}bool Start(){_isrunning = true;while (true){char inbuffer[1024]; // stringstruct sockaddr_in peer;socklen_t len = sizeof(peer); // 必须设定ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer)-1, 0, CONV(&peer),&len);if(n > 0){inbuffer[n] = 0;InetAddr client(peer);//获取cilent相关信息std::string cilentmessage = client.Ip()+":"+std::to_string(client.Port())+"# "+ inbuffer;LOG(LogLevel::DEBUG)<<cilentmessage;//调用回调方法处理翻译业务std::string value = _func(inbuffer);//将获取到的信息写回clientstd::string echo_string = "Translate# ";echo_string += value;::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,client.NetAddr(),client.NetAddrLen()); }}_isrunning = false;}~UdpServer(){if (_sockfd > gsockfd)::close(_sockfd);}private:InetAddr _addr; // 服务器地址包括ip和portint _sockfd;bool _isrunning; // 服务器运行状态func_t _func; //回调业务方法
};#endif
最后在定义服务器时使用lambda
表达式将Dict
类中的Translate
方法绑定给UdpServer
:
#include "UdpServer.hpp"
#include "Dict.hpp"using namespace DictionaryModule;// ./server_udp localport
int main(int argc, char *argv[])
{ENABLE_CONSOLE_LOG_STRATEGY();Dict dictionary;std::unique_ptr<UdpServer> svr_uptr;if (argc == 2){uint16_t port = std::stoi(argv[1]);svr_uptr = std::make_unique<UdpServer>([&dictionary](const std::string& key){return dictionary.Translate(key);},port);}elsesvr_uptr = std::make_unique<UdpServer>([&dictionary](const std::string& key){return dictionary.Translate(key);});svr_uptr->InitServer();svr_uptr->Start();return 0;
}
客户端函数不需要改变可以直接使用,结果如下:
3. ChatServer
对于聊天室的实现,我们需要对聊天对象进行管理,所以需要新建一个类usermanager
以及描述聊天对象的类user
:
#pragma once#include <iostream>
#include <list>
#include <memory>
#include <algorithm>
#include <sys/types.h>
#include <sys/socket.h>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "Mutex.hpp"
namespace UserModule
{using namespace InetAddrModule;using namespace LogModule;using namespace MutexModule;class UserInterface{public:virtual ~UserInterface() = default;virtual void SendTo(int sockfd, const std::string &message) = 0; // 纯虚函数virtual bool operator==(const InetAddr &u) const = 0;virtual std::string Id() = 0;};//描述对象class User : public UserInterface{public:User(const InetAddr &id) : _id(id){}void SendTo(int sockfd, const std::string &message) override{// ssize_t n = ::sendto(sockfd, &message, message.size(), 0, _id.NetAddr(), _id.NetAddrLen());错误错误!!!!不能取地址messagessize_t n = ::sendto(sockfd, message.c_str(), message.size(), 0, _id.NetAddr(), _id.NetAddrLen());LOG(LogLevel::DEBUG) << "send message to " << _id.Addr() << " info: " << message;if (n < 0){LOG(LogLevel::WARNING) << "Snedto fail...";return;}}bool operator==(const InetAddr &u) const override{return _id == u;}std::string Id(){return _id.Addr();}~User(){}private:InetAddr _id;};//管理对象class UserManage{public:UserManage(){}void AddUser(InetAddr &id){LockGuard lock(_mutex);//因为要访问公共资源所以要加锁保护// 1.先遍历整个链表查找是否已经添加过了for (auto &user : _online_user){if (*user == id) // User已经重载=={LOG(LogLevel::INFO) << id.Addr() << "用户已经存在...";return;}}// 2.如果是新用户就添加_online_user.push_back(std::make_shared<User>(id));LOG(LogLevel::INFO) << "添加用户: " << id.Addr() << "成功...";}void DelUser(InetAddr &id){LockGuard lock(_mutex);// 1.先遍历整个链表查找是否有该用户auto pos = std::remove_if(_online_user.begin(), _online_user.end(), [&id](std::shared_ptr<UserInterface> &user){ return *user == id; });// 2.如果有就删除_online_user.erase(pos, _online_user.end());}// 路由转发void Router(int sockfd, const std::string &message){LockGuard lock(_mutex);for (auto &user : _online_user){user->SendTo(sockfd, message);}}void PrintUser(){LockGuard lock(_mutex);for (auto user : _online_user){LOG(LogLevel::DEBUG) << "在线用户-> " << user->Id();}}~UserManage(){}private:std::list<std::shared_ptr<UserInterface>> _online_user;Mutex _mutex;};
};
对于描述对象参数我们可以使用之前实现的InetAddr类,对于对象的管理方法主要有添加对象、删除对象以及路由转发(群发)这三个部分;因为后续有多个线程而它们内部实现需要访问公共资源,所以需要加锁保护。
在服务器代码中其他都与前面类似,我们只需要将服务器的Start
方法修改一下即可:
bool Start(){_isrunning = true;while (true){char inbuffer[1024]; // stringstruct sockaddr_in peer;socklen_t len = sizeof(peer); // 必须设定ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);if (n > 0){inbuffer[n] = 0;InetAddr client(peer); // 1.获取cilent相关信息std::string message = client.Addr() + "# " + inbuffer;LOG(LogLevel::DEBUG) << message;// 2.判断是否为quit信息if (std::strcmp(inbuffer, "quit") == 0){_deluser(client);message = client.Addr() + "# " + "我走了,你们聊!";}else{// 3.添加新用户_adduser(client);}// 3. 构建转发任务,推送给线程池,让线程池进行转发task_t task = std::bind(UdpServer::_router, _sockfd, message);ThreadPool<task_t>::GetInstance()->Enqueue(task);}}_isrunning = false;}
服务器不再是简单的接收信息,还需要对接收的消息进行处理;因为转发任务消耗的时间可能较长,我们可以利用之前实现的线程池来处理多个转发任务,主线程则继续收消息然后往线程池里添加转发任务。
除了Start
方法,服务器类也需要添加几个回调方法(在Start
方法中使用):
using add_t = std::function<void(InetAddr &id)>;
using del_t = std::function<void(InetAddr &id)>;
using router_t = std::function<void(int sockfd, const std::string &message)>;
using task_t = std::function<void()>;
class UdpServer
{
public:UdpServer(add_t adduser, del_t deluser, router_t router, uint16_t port = gdefaultport): _sockfd(gsockfd),_addr(port),_isrunning(false),_adduser(adduser),_deluser(deluser),_router(router){}private:InetAddr _addr; // 服务器地址包括ip和portint _sockfd;bool _isrunning; // 服务器运行状态add_t _adduser;del_t _deluser;router_t _router;
};#endif
在main
函数中使用服务器对象时就需要绑定上述回调方法:
#include "UdpServer.hpp"
#include "User.hpp"
using namespace UserModule;// ./server_udp localport
int main(int argc, char *argv[])
{ENABLE_CONSOLE_LOG_STRATEGY();std::shared_ptr<UserManage> um = std::make_shared<UserManage>();std::unique_ptr<UdpServer> svr_uptr;if (argc == 2){uint16_t port = std::stoi(argv[1]);svr_uptr = std::make_unique<UdpServer>([&um](InetAddr &id){ return um->AddUser(id); },[&um](InetAddr &id){ return um->DelUser(id); },[&um](int sockfd, const std::string &message){ return um->Router(sockfd, message); },port);}elsesvr_uptr = std::make_unique<UdpServer>([&um](InetAddr &id){ return um->AddUser(id); },[&um](InetAddr &id){ return um->DelUser(id); },[&um](int sockfd, const std::string &message){ return um->Router(sockfd, message); });svr_uptr->InitServer();svr_uptr->Start();return 0;
}
对于客户端代码,我们也需要创建两个线程,主线程用来向服务器发送消息,另一个线程则用来接收群发的消息:
#include "Common.hpp"
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>int sockfd = -1;
struct sockaddr_in server;void ClientQuit(int signo)
{(void)signo;const std::string quit = "QUIT";int n = ::sendto(sockfd, quit.c_str(), quit.size(), 0, CONV(&server), sizeof(server));exit(0);
}void *Recver(void *args)
{while (true){(void)args;struct sockaddr_in temp;socklen_t len = sizeof(temp);char buffer[1024];int n = ::recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, CONV(&temp), &len);if (n > 0){buffer[n] = 0;std::cout << buffer << std::endl; // 代码没问题,重定向也没问题,管道读写同时打开,才会继续向后运行// fprintf(stderr, "%s\n", buffer);// fflush(stderr);}}
}// CS
// ./client_udp serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " serverip serverport" << std::endl;Die(USAGE_ERR);}signal(2, ClientQuit);std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);// 1. 创建socketsockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;Die(SOCKET_ERR);}std::cout<<"sockfd: "<<sockfd<<std::endl;// 1.1 填充server信息memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = ::htons(serverport);server.sin_addr.s_addr = ::inet_addr(serverip.c_str());pthread_t tid;pthread_create(&tid, nullptr, Recver, nullptr);// 1.2 启动的时候,给服务器推送消息即可const std::string online = " ... 来了哈!";int n = ::sendto(sockfd, online.c_str(), online.size(), 0, CONV(&server), sizeof(server));// 2. clientdonewhile (true){std::cout << "Please Enter# ";std::string message;std::getline(std::cin, message);// client 不需要bind吗?socket <-> socket// client必须也要有自己的ip和端口!但是客户端,不需要自己显示的调用bind!!// 而是,客户端首次sendto消息的时候,由OS自动进行bind// 1. 如何理解client自动随机bind端口号? 一个端口号,只能被一个进程bind// 2. 如何理解server要显示的bind?服务器的端口号,必须稳定!!必须是众所周知且不能改变轻易改变的!int n = ::sendto(sockfd, message.c_str(), message.size(), 0, CONV(&server), sizeof(server));(void)n;}return 0;
}
在运行客户端代码之前,我们可以创建一个管道将其重定向到cerro,然后运行客户端,这样服务器群发收到的消息就会写入到管道中
相关文章:

【Linux】Socket编程—UDP
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…...
2025年物联网相关专业毕业论文选题参考,文末联系,选题相关资料提供
一、智能穿戴解决方案研究方向 序号解决方案论文选题论文研究方向1智能腰带健康监测基于SpringBoot和Vue的智能腰带健康监测数据可视化平台开发研究如何利用SpringBoot和Vue技术栈开发一个数据可视化平台,用于展示智能腰带健康监测采集的数据,如心率、血…...

如何在WPS和Word/Excel中直接使用DeepSeek功能
以下是将DeepSeek功能集成到WPS中的详细步骤,无需本地部署模型,直接通过官网连接使用:1. 下载并安装OfficeAI插件 (1)访问OfficeAI插件下载地址:OfficeAI助手 - 免费办公智能AI助手, AI写作,下载…...

DeepSeek之Api的使用(将DeepSeek的api集成到程序中)
一、DeepSeek API 的收费模式 前言:使用DeepSeek的api是收费的 免费版: 可能提供有限的免费额度(如每月一定次数的 API 调用),适合个人开发者或小规模项目。 付费版: 超出免费额度后,可能需要按…...

使用DeepSeek实现AI自动编码
最近deepseek很火,低成本训练大模型把OpenAI、英伟达等股票搞得一塌糊涂。那它是什么呢,对于咱们程序员编码能有什么用呢?DeepSeek 是一款先进的人工智能语言模型,在自然语言处理和代码生成方面表现出色。它经过大量代码数据训练&…...

30~32.ppt
目录 30.导游小姚-介绍首都北京❗ 题目 解析 31.小张-旅游产品推广文章 题目 解析 32.小李-水的知识❗ 题目 解析 30.导游小姚-介绍首都北京❗ 题目 解析 新建幻灯片-从大纲-重置-检查设计→主题对话框→浏览主题:考生文件夹(注意&#x…...
Java的匿名内部类转为lamada表达式
在Java中,匿名内部类通常用于创建没有命名类的实例。例如,你可能需要创建一个实现了某个接口的匿名类,或者在需要重写某个方法时使用它。在Java 8及更高版本中,你可以使用Lambda表达式来替代传统的匿名内部类,使得代码…...

redis高级数据结构Stream
文章目录 背景stream概述消息 ID消息内容常见操作独立消费创建消费组消费 Stream弊端Stream 消息太多怎么办?消息如果忘记 ACK 会怎样?PEL 如何避免消息丢失?分区 Partition Stream 的高可用总结 背景 为了解决list作为消息队列是无法支持消息多播问题,Redis5.0…...
LeetCode781 森林中的兔子
问题描述 在一片神秘的森林里,住着许多兔子,但是我们并不知道兔子的具体数量。现在,我们对其中若干只兔子进行提问,问题是 “还有多少只兔子与你(指被提问的兔子)颜色相同?” 我们将每只兔子的…...
单硬盘槽笔记本更换硬盘
背景 本人的笔记本电脑只有一个硬盘槽,而且没有M.2的硬盘盒,只有一个移动硬盘 旧硬盘:512G 新硬盘:1T 移动硬盘:512G 参考链接:https://www.bilibili.com/video/BV1iP41187SW/?spm_id_from333.1007.t…...
EB生成配置的过程
EB Tresos Studio,简称EB,通过图形化的模式进行配置生成,并根据选项配置生成配置代码,即 MCAL 层各个模块的配置参数。 在 MCAL 代码中,分为静态代码和配置代码。静态代码,就是 AUTOSAR 规范内容,包含对硬件的封装以及标准化接口的封装;配置代码一般用于配置初始化结构…...
量化交易数据获取:xtquant库的高效应用
量化交易数据获取:xtquant库的高效应用 在量化交易领域,历史行情数据的重要性不言而喻。它不仅为策略回测提供基础,也是实时交易决策的重要参考。本文将介绍如何使用xtquant库来高效获取和处理历史行情数据。 技术背景与应用场景 对于量化…...
哨兵模式与 Redis Cluster:高可用 Redis 的深度剖析
深入探讨 Redis 高可用性解决方案:哨兵模式与 Redis Cluster 一、哨兵模式(Redis Sentinel)深入解析 (一)工作原理详解 哨兵模式通过一个或多个哨兵实例监控 Redis 主从复制集群,确保在主节点发生故障时…...

C++20新特性
作者:billy 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 前言 C20 是 C 标准中的一个重要版本,引入了许多新特性和改进,包括模块(Modules)、协程…...

电机实验曲线数据提取
处理Python 代码供参考: 1、曲线数据还原 import cv2 import numpy as np import matplotlib.pyplot as plt# 读取图像 image_path 1.png image cv2.imread(image_path) image_copy image.copy() # 创建图像副本,用于叠加显示# 转换为灰度图像 gray cv2.cvtCo…...

windows蓝牙驱动开发-调试及支持的HCI和事件
调试蓝牙配置文件驱动程序 开发蓝牙配置文件驱动程序时,可以使用驱动程序验证程序来协助其调试。 若要启用验证检查,必须为 Bthusb.sys 启用驱动程序验证程序。 如果不执行此操作,将禁用验证检查。 若要完全利用验证检查,请确保…...

Excel大数据量导入导出
github源码 地址(更详细) : https://github.com/alibaba/easyexcel 文档:读Excel(文档已经迁移) B 站视频 : https://www.bilibili.com/video/BV1Ff4y1U7Qc 一、JAVA解析EXCEL工具EasyExcel Java解析、生成Excel比较…...

Linux系统命令无法使用(glib库相关问题)
1.背景描述 Yum强制安装了一些软件,安装软件成功无报错,完成后不久突然发现系统出问题了,所有的命令无法使用了,如ls、mv、cat等基本命令报错。 relocation error: /lib64/libpthread.so.0: symbol_libc_dl_error_tsd …...

Qt修仙之路2-1 仿QQ登入 法宝初成
widget.cpp #include "widget.h" #include<QDebug> //实现槽函数 void Widget::login1() {QString userusername_input->text();QString passpassword_input->text();//如果不勾选无法登入if(!check->isChecked()){qDebug()<<"xxx"&…...

DeepSeek-V3 论文解读:大语言模型领域的创新先锋与性能强者
论文链接:DeepSeek-V3 Technical Report 目录 一、引言二、模型架构:创新驱动性能提升(一)基本架构(Basic Architecture)(二)多令牌预测(Multi-Token Prediction…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...

VSCode 没有添加Windows右键菜单
关键字:VSCode;Windows右键菜单;注册表。 文章目录 前言一、工程环境二、配置流程1.右键文件打开2.右键文件夹打开3.右键空白处打开文件夹 三、测试总结 前言 安装 VSCode 时没有注意,实际使用的时候发现 VSCode 在 Windows 菜单栏…...