当前位置: 首页 > news >正文

【计算机网络】UDP协议编写群聊天室----附代码

UDP构建服务器 x

预备知识

认识UDP协议

此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论.

  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报
网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏
移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  • TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;
   #include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);uint16_t htons(uint16_t hostshort);uint32_t ntohl(uint32_t netlong);uint16_t ntohs(uint16_t netshort);
  • 这些函数名很好记,h表示host(本地),n表示network(网络),l表示32位长整数,s表示16位短整数
  • 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
  • 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回 。
socket编程接口

``// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器) int socket(int domain, int type, int protocol);`

// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);*

// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);

// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);

// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockaddr结构
  • Pv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址.1

  • IPv4、 IPv6地址类型分别定义为常数AF_INET、 AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.

  • socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数;

    有sockaddr 结构,sockaddr_in 结构, sockaddr_un 结构

sockaddr_in 结构 用于网络中通讯。

sockaddr_un 结构 用于本地进程间的通信。

我们应该要知道的是,sockaddr 结构,sockaddr_in 结构, sockaddr_un 结构,构成了多态

sockaddr 结构是基类,sockaddr_in 结构, sockaddr_un 结构是衍生类。

我们现在只需要了解sockaddr_in 结构。

在这里插入图片描述

构建服务器

初始化服务器

1 .创建socket接口,打开网络文件

2 .给服务器指明IP 和 PORT

3 .bind 将 sockaddr 套接字字段和 网络文件描述符 进行绑定

代码:

void Init(){//1. 创建socket接口,打开网络文件_sock=socket(AF_INET,SOCK_DGRAM,0);if(_sock==-1){std::cerr<<"socket error"<<strerror(errno)<<std::endl;exit(SOCKET_ERR);}std::cout<<"creat socket success:"<<_sock<<std::endl;//2.给服务器指明IP 和 PORTstruct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family=AF_INET;//端口号和IP地址都需要通过网络发送给目标,所以需要转换成网络序列local.sin_port=htons(_port);//字符串风格的IP需要转换成4字节int   ,1.1.1.1 -》》intlocal.sin_addr.s_addr=INADDR_ANY;//char* 类型的 c_str();//此时的 local 还只是一个临时变量// bind 将 addr套接字字段和 网络文件描述符 进行绑定if(bind(_sock,(sockaddr*)&local,sizeof(local))==-1){std::cerr<<"bind error"<<strerror(errno)<<std::endl;exit(BIND_ERR);}std::cout<<"bind success"<<std::endl;}

到这里,我们服务器的初始化就算成功了,接下来就是启动服务器了.

启动服务器

我们需要接收来自客户端的消息,并将消息进行处理后返回给客户端。

这就意味着,服务器需要有最基础的两项功能,

接收网络消息,并在网络上发送消息

  • 定义一个缓冲区,里面用来存储接收的消息
  • 我们同时也需要知道是谁给我发送的消息,定义一个sockaddr_in 结构,用于保存客户的IP和PORT
  • 最后,将消息返回给客户端

代码:

 void Start(){char buffer[1024];while(true){struct sockaddr_in client;socklen_t len=sizeof(client);//client是一个接收型参数,存储了给服务器发送消息的客户端的IP+端口号int n=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(sockaddr*)&client,&len);if(n>0) buffer[n]='\0';else continue;std::string clientIp=inet_ntoa(client.sin_addr);int clientport=ntohs(client.sin_port);std::cout<<clientIp<<'-'<<clientport<<" "<<"client echo#"<<buffer<<std::endl;sendto(_sock,buffer,strlen(buffer),0,(sockaddr*)&client,len);}}

整个服务端的简易编写就此完成:

代码:

udp_server.hpp

#pragma once 
#include<sys/socket.h>
#include<sys/types.h>
#include<iostream>
#include<cstring>
#include<errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include"err.hpp"class UdpServer{
public:public:static const u_int16_t DEFAULT_PORT=8080;UdpServer(uint16_t port=DEFAULT_PORT):_port(port){std::cout<<"PORT:"<<_port<<std::endl;}void Init(){//1. 创建socket接口,打开网络文件_sock=socket(AF_INET,SOCK_DGRAM,0);if(_sock==-1){std::cerr<<"socket error"<<strerror(errno)<<std::endl;exit(SOCKET_ERR);}std::cout<<"creat socket success:"<<_sock<<std::endl;//2.给服务器指明IP 和 PORTstruct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family=AF_INET;//端口号和IP地址都需要通过网络发送给目标,所以需要转换成网络序列local.sin_port=htons(_port);//字符串风格的IP需要转换成4字节int   ,1.1.1.1 -》》intlocal.sin_addr.s_addr=INADDR_ANY;//char* 类型的 c_str();//此时的 local 还只是一个临时变量// bind 将 addr套接字字段和 网络文件描述符 进行绑定if(bind(_sock,(sockaddr*)&local,sizeof(local))==-1){std::cerr<<"bind error"<<strerror(errno)<<std::endl;exit(BIND_ERR);}std::cout<<"bind success"<<std::endl;}void Start(){char buffer[1024];while(true){struct sockaddr_in client;socklen_t len=sizeof(client);//client是一个接收型参数,存储了给服务器发送消息的客户端的IP+端口号int n=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(sockaddr*)&client,&len);if(n>0) buffer[n]='\0';else continue;std::string clientIp=inet_ntoa(client.sin_addr);int clientport=ntohs(client.sin_port);std::cout<<clientIp<<'-'<<clientport<<" "<<"client echo#"<<buffer<<std::endl;sendto(_sock,buffer,strlen(buffer),0,(sockaddr*)&client,len);}}private:int _sock;uint16_t _port;//std::string _ip;//  云服务器,或者一款服务器,一般不要指明某一个确定的IP, 让我们的udpserver在启动的时候,bind本主机上的任意IP
};

udp_server.cc

#include"udp_server.hpp"
#include<iostream>
#include<memory>using namespace std;static void usage(string prc)
{cout<<"Usage\n\t"<<prc<<"port\n"<<endl;
}int main(int argc,char* argv[])
{if(argc!=2){usage(argv[0]);exit(USAGE_ERR);}uint16_t port=atoi(argv[1]);unique_ptr<UdpServer> us(new UdpServer(port));us->Init();us->Start();return 0;
}
客户端简易实现

接下来我们进行客户端的编写,客户端的编写基本按照服务端的端口来进行

现阶段也是只需要向服务端发送消息,接收服务端的消息这两种功能

流程:

  • 创建套接字
  • 我们要向客户端发送消息,需要知道其IP和PORT,所以需要一个sockaddr_in结构,填充的是服务端的信息
  • 然后就是发送消息和接收消息

但是客户端的编写有一些需要注意的地方

1.服务端的端口号和IP地址都sh是需要我们自己绑定的,那么客户端需要吗?
答:客户端也是需要绑定的,但是不需要我们自己手动绑定,而是OS帮我们进行操作。
原因:client的port要随机让OS分配防止client出现启动冲突(例如:我们的手机终端上有很多的软件(客户端),如果自己bind,会可能导致某些服务的端口号被占用,无法启动)

2.服务端为什么需要自己绑定?
原因:
1. server的端口不能随意改变,众所周知且不能随意改变的
2. 同一家公司的port号需要统一规范化

代码:
udp_client.cc

#include<sys/socket.h>
#include<sys/types.h>
#include<iostream>
#include<cstring>
#include<errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include"err.hpp"
using namespace std;//127.0.0.1(本地回环) 表示的是当前主机,用于进行本地通讯或者测试
static void Usage(string prc)
{cout<<"Usage\t\n"<<prc<<" serverip serverport\n"<<endl;
}int main(int argc,char* argv[])//./server 目标IP 目标PORT
{if(argc!=3){Usage(argv[0]);exit(USAGE_ERR);}string serverip=argv[1];uint16_t serverport=atoi(argv[2]);int sock=socket(AF_INET,SOCK_DGRAM,0);if(sock<0){cerr<<"socket fail"<<strerror(errno)<<endl;exit(SOCKET_ERR);}struct sockaddr_in server;//目标服务器的IP+PORTmemset(&server,0,sizeof(server));server.sin_family=AF_INET;server.sin_port=htons(serverport);server.sin_addr.s_addr=inet_addr(serverip.c_str());while(true){char buffer[1024];cout<<"请输入#";cin>>buffer;//1. client 这里要不要bind呢?要的!socket通信的本质[clientip:clientport, serverip:serverport]// 2.client不需要自己bind,也不要自己bind,操作系统自动给我们进行bind -- 为什么?client的port要随机让OS分配防止client出现启动冲突(我们的手机终端上有很多的软件(客户端),如果自己bind,会可能导致某些服务的端口号被占用,无法启动)// 3.server 为什么要自己bind?1. server的端口不能随意改变,众所周知且不能随意改变的 2. 同一家公司的port号需要统一规范化sendto(sock,buffer,strlen(buffer),0,(sockaddr*)&server,sizeof(server));char Rebuffer[1024];sockaddr_in tmp;socklen_t len=sizeof(tmp);int n=recvfrom(sock,Rebuffer,sizeof(Rebuffer)-1,0,(sockaddr*)&tmp,&len);if(n>0) Rebuffer[n]='\0';std::cout<<serverip<<'-'<<serverport<<" "<<"server echo#"<<Rebuffer<<std::endl;}return 0;
}

好需要对错误码进行处理:
err.hpp

#pragma onceenum ERR{SOCKET_ERR=1,BIND_ERR,USAGE_ERR
};

在服务器中,我们实现了一个简单的echo型服务器,就不对消息进行处理,只是进行将消息简单的返回。

实现效果
在这里插入图片描述

构建一个群聊系统

在之前建设的服务器基础上,进行加工处理,便可以实现一个简易的群聊功能
我们可以这么理解群聊:

就是你把自己的消息发送给服务器,服务器在转发给每一个在群聊中的人

所以我们需要做如下改动:

  1. 需要一个储存客户消息的容器,把连接过来的客户都sockaddr_in结构保存
  2. 还需要一个缓冲区,保存发送过来的消息
  3. 同时需要注意的是,不同的客户来对同一个缓冲区发送消息,会有多线程并发的问题,需要加锁
  4. 服务器也需要进行多线程化,因为单一进程会阻塞在接收或者发送消息上

组件
RingQueue.hpp

#pragma once#include<pthread.h>
#include<semaphore.h>
#include<vector>const int DEFAULT_CAP=10; 
template<class T>
class RingQueue{
public:RingQueue(int num=DEFAULT_CAP):_cap(num),_rq(num),_consume_step(0),_produce_step(0){sem_init(&_consume_sem,0,0);sem_init(&_produce_sem,0,_cap);}~RingQueue(){sem_destroy(&_consume_sem);sem_destroy(&_produce_sem);}void lock(pthread_mutex_t& m){pthread_mutex_lock(&m);}void unlock(pthread_mutex_t& m){pthread_mutex_unlock(&m);}void P(sem_t& s){sem_wait(&s);}void V(sem_t& s){sem_post(&s);}void push(const T& in){P(_produce_sem);lock(_produce_mutex);_rq[_produce_step++]=in;_produce_step%=_cap;unlock(_produce_mutex);V(_consume_sem);}void pop(T* out){P(_consume_sem);lock(_consume_mutex);*out=_rq[_consume_step++];_consume_step%=_cap;unlock(_consume_mutex);V(_produce_sem);}private:std::vector<T> _rq;int _cap;//消费者和生产者之间的同步关系通过信号量进行调节sem_t _consume_sem;sem_t _produce_sem;//当多线程运行时,生产者和生产者,消费锁者和消费者之间的互斥关系需要通过锁来维持pthread_mutex_t _consume_mutex;pthread_mutex_t _produce_mutex;int _consume_step;int _produce_step;
};

Thread.hpp

#pragma once#include <pthread.h>
#include <iostream>
#include <string>
#include <string.h>
#include <functional>using namespace std;string to_hex(uint64_t n)
{char arr[32];snprintf(arr, sizeof(arr), "0x%x", n);return arr;
}
class Thread
{
public:// typedef void(*func_t)();using func_t = std::function<void()>;typedef enum{NEW = 0,RUNNING,EXISTED} ThreadStatus;Thread(int num, func_t func) : _tid(0), _func(func){char name[108];snprintf(name, sizeof(name), "thread-%d", num);_name = name;_status = NEW;}static void *runHelper(void *args){Thread *ts = (Thread *)args;ts->_func();return nullptr;}void run(){int n = pthread_create(&_tid, nullptr, runHelper, this);if (n != 0){exit(1);}_status = RUNNING;}int get_status(){return _status;}void join(){int n = pthread_join(_tid, nullptr);if (n != 0)exit(2);cout << _name << " "<< "has joined" << endl;_status = EXISTED;}const string &get_name(){return _name;}string get_id(){return to_hex(_tid);}// pthread_t get_id()// {//     return _tid;// }~Thread(){}private:pthread_t _tid;string _name;ThreadStatus _status;func_t _func;// void* _args;//函数调用时需要传的参数
};

err.hpp

#pragma onceenum ERR{SOCKET_ERR=1,BIND_ERR,USAGE_ERR
};

代码:
udp_server.hpp

#pragma once
#include <sys/socket.h>
#include <sys/types.h>
#include <iostream>
#include <cstring>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
#include <pthread.h>
#include "RingQueue.hpp"
#include "LockGuard.hpp"
#include "Thread.hpp"
#include "err.hpp"using func_t = std::function<std::string(std::string)>;class UdpServer
{
public:
public:static const u_int16_t DEFAULT_PORT = 8080;UdpServer(uint16_t port = DEFAULT_PORT) : _port(port){std::cout << "PORT:" << _port << std::endl;pthread_mutex_init(&_lock, nullptr);// p=new Thread(1,);p = new Thread(1, std::bind(&UdpServer::Receive, this));c = new Thread(1, std::bind(&UdpServer::send, this));}void Start(){// 1. 创建socket接口,打开网络文件_sock = socket(AF_INET, SOCK_DGRAM, 0);if (_sock == -1){std::cerr << "socket error" << strerror(errno) << std::endl;exit(SOCKET_ERR);}std::cout << "creat socket success:" << _sock << std::endl;// 2.给服务器指明IP 和 PORTstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;// 端口号和IP地址都需要通过网络发送给目标,所以需要转换成网络序列local.sin_port = htons(_port);// 字符串风格的IP需要转换成4字节int   ,1.1.1.1 -》》intlocal.sin_addr.s_addr = INADDR_ANY; // char* 类型的 c_str();// 此时的 local 还只是一个临时变量//  bind 将 addr套接字字段和 网络文件描述符 进行绑定if (bind(_sock, (sockaddr *)&local, sizeof(local)) == -1){std::cerr << "bind error" << strerror(errno) << std::endl;exit(BIND_ERR);}std::cout << "bind success" << std::endl;p->run();c->run();}void Add_user(std::string ip, int port, struct sockaddr_in user){std::string name = ip + " + " + to_string(port);LockGuard lockguard(&_lock);_online[name] = user;}void Receive(){char buffer[1024];while (true){struct sockaddr_in client;socklen_t len = sizeof(client); // client是一个接收型参数,存储了给服务器发送消息的客户端的IP+端口号int n = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&client, &len);if (n > 0)buffer[n] = '\0';elsecontinue;std::string clientIp = inet_ntoa(client.sin_addr);int clientport = ntohs(client.sin_port);Add_user(clientIp, clientport, client);_rq.push(buffer);std::cout << clientIp << '-' << clientport << " "<< "client echo#" << buffer << std::endl;}}void send(){while (true){std::string message;_rq.pop(&message);LockGuard lockguard(&_lock);//访问临界资源,需要锁for (auto &user : _online){sendto(_sock, message.c_str(), strlen(message.c_str()), 0, (sockaddr *)&user.second, sizeof(user.second));}}}~UdpServer(){pthread_mutex_destroy(&_lock);p->join();c->join();}private:int _sock;uint16_t _port;func_t _server;std::unordered_map<std::string, sockaddr_in> _online;RingQueue<std::string> _rq;pthread_mutex_t _lock;Thread *p;Thread *c;// std::string _ip;//  云服务器,或者一款服务器,一般不要指明某一个确定的IP, 让我们的udpserver在启动的时候,bind本主机上的任意IP
};

udp_server.cc

#include "udp_server.hpp"
#include <iostream>
#include <memory>using namespace std;static void usage(string prc)
{cout << "Usage\n\t" << prc << "port\n"<< endl;
}bool isPass(const string &command)
{bool pass = true;auto pos = command.find("rm");if (pos != std::string::npos)pass = false;pos = command.find("mv");if (pos != std::string::npos)pass = false;pos = command.find("while");if (pos != std::string::npos)pass = false;pos = command.find("kill");if (pos != std::string::npos)pass = false;return pass;
}
string excuteCommand(const string &s)
{// 可能有些人会传递一些比较恶劣的代码,如rm ,所以我们需要进行安全检查if (!isPass(s))return "you are a bad man!";FILE *fp = popen((s.c_str()), "r");if (fp == NULL)return "None";// 获取结果string result;char line[2048];while (fgets(line, sizeof(line), fp) != NULL){result += line;}pclose(fp);return result;
}int main(int argc, char *argv[])
{if (argc != 2){usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);// unique_ptr<UdpServer> us(new UdpServer(excuteCommand,port));unique_ptr<UdpServer> us(new UdpServer(port));us->Start();return 0;
}

udp_client.cc

#include <iostream>
#include <bits/stdc++.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include "Thread.hpp"
#include "err.hpp"
#include <cstring>using namespace std;// 127.0.0.1(本地回环) 表示的是当前主机,用于进行本地通讯或者测试
static void Usage(string prc)
{cout << "Usage\t\n"<< prc << " serverip serverport\n"<< endl;
}void *recver(void *args)
{int sock = *(static_cast<int *>(args));while (true){// 接受char buffer[2048];struct sockaddr_in temp;socklen_t len = sizeof(temp);int n = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len);if (n > 0){buffer[n] = 0;std::cout << buffer << std::endl; // 1}}
}int main(int argc, char *argv[]) //./server 目标IP 目标PORT
{if (argc != 3){Usage(argv[0]);exit(USAGE_ERR);}string serverip = argv[1];uint16_t serverport = atoi(argv[2]);int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){cerr << "socket fail" << strerror(errno) << endl;exit(SOCKET_ERR);}struct sockaddr_in server; // 目标服务器的IP+PORTmemset(&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, &sock);while (true){char buffer[1024];cout << "请输入#";// cin>>buffer;cin.getline(buffer, 1024);// 1. client 这里要不要bind呢?要的!socket通信的本质[clientip:clientport, serverip:serverport]// 2.client不需要自己bind,也不要自己bind,操作系统自动给我们进行bind -- 为什么?client的port要随机让OS分配防止client出现启动冲突(我们的手机终端上有很多的软件(客户端),如果自己bind,会可能导致某些服务的端口号被占用,无法启动)// 3.server 为什么要自己bind?1. server的端口不能随意改变,众所周知且不能随意改变的 2. 同一家公司的port号需要统一规范化sendto(sock, buffer, strlen(buffer), 0, (sockaddr *)&server, sizeof(server));}return 0;
}

展示效果:

在这里插入图片描述

相关文章:

【计算机网络】UDP协议编写群聊天室----附代码

UDP构建服务器 x 预备知识 认识UDP协议 此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面再详细讨论. 传输层协议无连接不可靠传输面向数据报 网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的…...

Java架构师高并发架构设计

目录 1 导学2 什么是高并发问题3 高并发处理之道4 akf扩展立方体5 细化理念应对高并发5 总结1 导学 本章的主要内容是大型系统架构设计的难点之一,高并发架构设计相关的知识落到实际项目上,就是订单系统的高并发架构设计。我们首先会去学习到底何为高并发问题,先把问题搞清楚…...

【客观赋权法1】熵权法(MATLAB全代码)

熵权法(entropy weight method, EWM) 1 原理2 MATLAB代码3 案例参考赋权法(Weighting Method) 是一种常用的数据处理方法,它可以将不同变量之间的重要性进行区分,并赋予它们不同的权重,以反映它们对整体的贡献程度。 指标在评估体系中的重要程度可以用 指标权重系数表示…...

“注释: 爱恨交织的双重标准?解析注释在代码开发中的作用。”

文章目录 每日一句正能量前言观点和故事程序员不写注释的原因是什么如何才能写出漂亮的注释后记 每日一句正能量 水与水之间有距离&#xff0c;但地心下直相牵&#xff0c;人与人之间有距离&#xff0c;但心里时刻挂念&#xff0c;发条短信道声晚安&#xff0c;梦里我们相见。 …...

一种基于局部适应度景观的进化规划的混合策略

文章目录 标题摘要结论研究背景研究内容、成果常用基础理论知识潜在研究点文献链接标题 A Mixed Strategy for Evolutionary Programming Based on Local Fitness Landscape 摘要 进化规划(EP)的性能受到许多因素的影响(如突变操作符和选择策略)。虽然传统的高斯突变算子…...

Python数据攻略-Mongodb数仓无法写入方法汇总

Mongodb作为一个非结构化的NoSQL数据库,能存储各种复杂和多变的数据格式,如JSON。这使得Mongodb在实时数据分析和高性能查询中具有优势。 在使用Mongodb的过程中,可能会遇到写入失败的问题。常见的几种情况包括无法建立连接、认证失败和存储限制。 文章目录 诊断问题日志分…...

用什么工具来画UML?

2023年10月9日&#xff0c;周一晚上 目录 我的决定 关于rational rose UML工具有哪些 相关资料 我的决定 我决定用plantUML、draw.io或starUML就可以了 其实没必要在意工具&#xff0c; 重要的是能把图画出来、把图画好画规范&#xff0c; 重要的是知道怎么去画图、把意…...

SQLite3数据类型

存储类与数据类型 NULLINTEGER 有符号整数类型&#xff0c;存储为0,1,2,3,4,6或8个字节&#xff0c;取决于值的大小。REAL 浮点类型&#xff0c;存储为8字节的IEEE浮点数。TEXT 文本类型&#xff0c;将使用数据库指定的编码格式存储&#xff08;UTF-8,UTF-16BE,UTF-16LE)BLOB …...

K8S:K8S对外服务之Ingress

文章目录 一.Ingress基础介绍1.Ingress概念2.K8S对外暴露服务&#xff08;service&#xff09;主要方式&#xff08;1&#xff09;NodePort&#xff08;2&#xff09;LoadBalancer&#xff08;3&#xff09;externalIPs&#xff08;4&#xff09;Ingress 3.Ingress 组成&#x…...

flask入门

第一个Flask项目 创建后项目如下图 static存放静态文件&#xff0c;templates存放Jinja2模板&#xff0c;app.py是整个项目的入口文件 我们略微理解下app.py这里的代码 # 从flask这个包中导入Flask类 from flask import Flask#使用Flask类创建一个app对象 #__name__:代表当前…...

掌动智能:性能测试工具优势有哪些

由于应用程序的性能直接影响用户体验和满意度。而性能问题可能会导致应用响应缓慢、崩溃或无法处理大量用户请求。为了确保应用程序的高性能和可靠性&#xff0c;开发团队需要对应用程序进行性能测试。性能测试工具能够模拟真实场景下的负载并监测应用程序的性能表现&#xff0…...

实现一个简单的线性回归和多项式回归(2)

对于多项式回归&#xff0c;可以同样使用前面线性回归中定义的LinearRegression算子、训练函数train、均方误差函数mean_squared_error&#xff0c;生成数据集create_toy_data,这里就不多做赘述咯~ 拟合的函数为 def sin(x):y torch.sin(2 * math.pi * x)return y1.数据集的建…...

云原生Kubernetes:K8S集群kubectl命令汇总

目录 一、理论 1.概念 2. kubectl 帮助方法 3.kubectl 子命令使用分类 4.使用kubectl 命令的必要环境 5.kubectl 详细命令 一、理论 1.概念 kubectl是一个命令行工具&#xff0c;通过跟 K8S 集群的 API Server 通信&#xff0c;来执行集群的管理工作。 kubectl命令是操…...

Java使用模板导出word、pdf

使用deepoove根据模板导出word文档&#xff0c;包括文本、表格、图表、图片&#xff0c;使用WordConvertPdf可将word文档转换为pdf导出 模板样例&#xff1a; 导出结果&#xff1a; 一、引入相关依赖 <!-- 工具类--><dependency><groupId>cn.hutool&…...

速通Redis基础(二):掌握Redis的哈希类型和命令

目录 Redis 哈希类型简介 Redis 哈希命令 HSET HGET HEXISTS HDEL HKEYS HVALS HGETALL HMGET HLEN HSETNX ​编辑 HINCRBY HINCRBYFLOAT Redis的哈希类型命令小结 Redis 是一种高性能的键值存储数据库&#xff0c;支持多种数据类型&#xff0c;其中之…...

WebDAV之π-Disk派盘 + 书藏家

书藏家是一款书籍收藏的软件,对于喜欢阅读书籍的用户来说非常友好,记录你所阅读的书籍内容,对你所阅读的书籍内容进行全方位的管理,并且支持多种录入的方式,不管是实体书籍还是网络书籍都能够进行更为有效的管理;内置WebDAV 模块,更加便利的整理自己的文件资源;书藏家的…...

香港Web3.0生态现状

目前香港Web3.0生态正在快速发展。香港政府和金融机构正在积极推动Web3.0生态的建设&#xff0c;以推动数字经济和智慧城市的发展。香港政府已经发布了有关虚拟资产发展的政策宣言&#xff0c;鼓励和监管并重&#xff0c;加大力度推动虚拟资产产业向前发展。同时&#xff0c;香…...

LLMs之BELLE:源码解读(sft_train.py文件)

LLMs之BELLE:源码解读(sft_train.py文件) 目录 源码解读(sft_train.py文件) # 1、解析命令行参数,包括模型参数、数据参数和训练参数。...

【UE5 Cesium】17-Cesium for Unreal 建立飞行跟踪器(2)

目录 效果 步骤 一、飞机沿航线飞行 二、通过切换相机实现在不同角度观察飞机飞行 效果 步骤 一、飞机沿航线飞行 先去模型网站下载一个波音737飞机模型 然后将下载好的模型导入到UE项目中&#xff0c;导入时需要勾选“合并网格体”&#xff08;导入前最好在建模软件中将…...

【ElasticSearch】基于 Java 客户端 RestClient 实现对 ElasticSearch 索引库、文档的增删改查操作,以及文档的批量导入

文章目录 前言一、对 Java RestClient 的认识1.1 什么是 RestClient1.2 RestClient 核心类&#xff1a;RestHighLevelClient 二、使用 Java RestClient 操作索引库2.1 根据数据库表编写创建 ES 索引的 DSL 语句2.2 初始化 Java RestClient2.2.1 在 Spring Boot 项目中引入 Rest…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...