47 tcp网络程序

网路聊天

API详解

下面用到的API,都在sys/socket.h中

socket ():
在这里插入图片描述

  • socket() 打开一个网络通讯端口,如果成功的话,就像open() 一样返回一个文件描述符
  • 应用程序可以像读文件一样用read/write在网络上收发数据
  • 如果调用出错返回-1
  • 对于IPv4,family参数指定为AF_INET
  • 对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议
  • protocol参数是传输层协议,填0默认匹配

bind ()
在这里插入图片描述

  • 服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后,就可以向服务器发起连接,服务器需要调用bind绑定一个固定的网络地址和端口号
  • bind() 成功返回0,失败返回-1
  • 作用是将参数sockfd和myaddr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听nyaddr所描述的地址和端口号
  • struct sockaddr* 是一个通用指针类型,myaddr参数实际上可以接收各种协议 的sockaddr结构体,而他们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度

myaddr初始化:
1.整个结构体清零
2.设置地址类型为AF_INET
3.网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个ip地址
4.端口号为SERV_PORT,可以定义为9999

listen ()
在这里插入图片描述

  • listen() 声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略,这里设置不会太大(一般是5)
  • listen() 成功返回0,失败返回-1

accept ()

在这里插入图片描述

  • 三次握手完成后,服务器调用accept接收连接
  • 如果服务器调用accept时还没有客户端的 连接请求,就阻塞等待直到有客户端连接上来
  • addr是一个传出参数,accept返回时传出客户端的地址和端口号
  • 如果给addr传递NULL,表示不关心客户端的地址
  • addrlen参数是一个传入传出参数(value-result arument),传入的是调用者提供的,缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地质结构体的实际长度(有可能没有占满调用者提供的缓冲区)

connect ()
在这里插入图片描述

  • 客户端需要调用connect连接服务器
  • connct和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址
  • 成功返回0,出错返回-1

服务端

成员变量三个,分别是listen套接字,ip和端口号,服务端的ip和端口号必须固定
在这里插入图片描述
构造函数传入ip和地址初始化成员变量
在这里插入图片描述
init函数初始化套接字信息,绑定到设备上,和前面的udp一样
因为tcp是面向字节流的,一般比较被动,处于一种等待连接来的状态,所以要设置等待连接,listen状态:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

run函数开始接收消息,创建和套接字的连接,返回新的套接字描述符,用来后面通讯

为什么会有两个套接字
这个就像饭店拉客的例子,饭店门口有一个吆喝顾客进去吃饭的服务员,当接受这个建议后,进到店里,会重新分配一个服务员提供后续服务,点餐等,吆喝的服务员又会继续在门口等待下一个顾客

listen套接字是拉客的服务员,确保服务端需要通信,后续的发送和接收由accept创建的新套接字完成

在这里插入图片描述
service函数发送和接收消息,传入套接字,ip和port用来显示用户。tcp字节流读写可以直接用read和write函数
在这里插入图片描述

测试
开启服务端,服务端使用telnet命令,使用本机环回地址连接

telnet [ip] [端口]
在这里插入图片描述

接着输入^]就可以输入消息
在这里插入图片描述

#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "log.hpp"string defaultip = "0.0.0.0";
uint16_t defaultport = 8000;
const int back = 2;  //连接请求队列个数,一般2-4Log log;enum
{SOCK_ERR = 1,BIND_ERR,LIStEN_ERR
};class server
{
public:server(const string ip = defaultip, const uint16_t port = defaultport){_ip = defaultip;_port = defaultport;}void init(){_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){log.logmessage(fatal, "socket create error");exit(SOCK_ERR);}log.logmessage(info, "socket create success:%d", _listensock);sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;inet_aton(_ip.c_str(), &local.sin_addr);local.sin_port = htons(_port);//绑定if (bind(_listensock, (const struct sockaddr*)&local, sizeof(local)) < 0){log.logmessage(fatal, "bind error");exit(BIND_ERR);}log.logmessage(fatal, "bind success");//tcp面向连接,服务器一般被动,处于一种等待连接到来的状态// 设置listen状态if (listen(_listensock, back) < 0){log.logmessage(fatal, "listen error");exit(LIStEN_ERR);}}void service(int fd, const string ip, const uint16_t port){cout << "welcome " << ip << endl;char message[1024];while (true){    ssize_t n = read(fd, message, sizeof(message) - 1);if (n > 0){message[n] = 0;//数据处理string echo_string;echo_string = "[" + ip + ":" + to_string(port) + "]: " + message;cout << echo_string << endl;write(fd, echo_string.c_str(), echo_string.size());}}}void run(){while (true){//获取链接sockaddr_in sock;socklen_t len;int sockfd = accept(_listensock, (sockaddr *)&sock, &len);if (sockfd < 0){log.logmessage(warning, "accept fail");continue;}char buff[32];string clientip = inet_ntop(AF_INET, &sock.sin_addr, buff, len);uint16_t clientport = ntohs(sock.sin_port);service(sockfd, clientip, clientport);close(sockfd);}}~server(){close(_listensock);}private:int _listensock;string _ip;uint16_t _port;
};

客户端

初始化addr协议内容
在这里插入图片描述套接字
在这里插入图片描述

conncect函数建立连接
在这里插入图片描述

读写消息
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <fcntl.h>using namespace std;// string path = "/dev/pts/5";
// struct thread_data
// {
//     int _sockfd;
//     struct sockaddr_in _server;
//     string _ip;
// };// void *send_message(void * temp)
// {
//     thread_data *td = (struct thread_data*)temp;
//     string message;
//     cout << "welcome " << td->_ip << endl;
//     while (true)
//     {
//         cout << "please enter: ";
//         getline(cin, message);
//         sendto(td->_sockfd, message.c_str(), message.size(), 0, (const sockaddr *)&td->_server, sizeof(td->_server));
//     }// }// void* recv_message(void* temp)
// {
//     // int fd = open(path.c_str(), O_WRONLY);
//     // if (fd < 0)
//     // {
//     //     perror("open");
//     // }//     // dup2(fd, 2);//     thread_data *td = (struct thread_data *)temp;
//     char buff[1024];
//     sockaddr_in rec;
//     socklen_t len = sizeof(rec);
//     while (true)
//     {
//         ssize_t s = recvfrom(td->_sockfd, buff, sizeof(buff) - 1, 0, (sockaddr *)&rec, &len);
//         if (s > 0)
//         {
//             buff[s] = 0;
//             cerr << buff << endl;
//         }
//     }//     //close(fd);
// }int main()
{//thread_data td;//ip和port可以通过命令行参数传入uint16_t port = 8000;string ip = "ip";struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(ip.c_str());server.sin_port = htons(port);int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){cout << "socket error" << endl;}//建立连接if (connect(sockfd, (const struct sockaddr*)&server, sizeof(server)) < 0){cout << "connect error" << endl;}cout << "connect success" << endl;// 通信string message;char buff[1024];while (true){cout << "please enter:";getline(cin, message);write(sockfd, message.c_str(), message.size());ssize_t n = read(sockfd, buff, sizeof(buff) - 1);if (n > 0){buff[n] = 0;cout << buff << endl;}}// client 需要绑定,但不显示绑定,由os自由选择//  pthread_t tid_send;//  pthread_t tid_recv;//  pthread_create(&tid_send, nullptr, send_message, &td);//  pthread_create(&tid_recv, nullptr, recv_message, &td);// pthread_join(tid_send, nullptr);// pthread_join(tid_recv, nullptr);close(sockfd);
}

多进程版

上面的程序是单进程的,主进程会跟随sevice程序直到结束,只能提供一个客户链接。需要可以多个用户同时连接的
在service函数的时候fork子进程,让子进程去执行功能,双方关闭不需要的文件,子进程关闭listen套接字,父进程关闭sockfd套接字,互不影响。但父进程会卡在回收子进程的wait函数里,可以用非阻塞的等待,保存打开过的套接字轮询。还可以在fork的子进程里再一次fork,fork成功后子进程退出,这样代替执行功能的就是孙子进程,孙子进程会被os领养,结束后自动释放,同时设置进程退出信号为忽视,就不需要等待子进程

void run(){//忽视子进程signal(SIGCHLD, SIG_IGN);while (true){//获取链接sockaddr_in sock;socklen_t len;int sockfd = accept(_listensock, (sockaddr *)&sock, &len);if (sockfd < 0){log.logmessage(warning, "accept fail");continue;}char buff[32];string clientip = inet_ntop(AF_INET, &sock.sin_addr, buff, len);uint16_t clientport = ntohs(sock.sin_port);pid_t pid = fork();if (pid == 0){// 子进程,孙子进程执行,子进程直接回收if (fork() > 0)exit(0); // 孙子进程,system领养service(sockfd, clientip, clientport);close(_listensock);exit(0);}// 父进程pid_t ret = waitpid(pid, nullptr, 0);close(sockfd);}}

可以从函数开始就for循环fork,每一个子进程都会从listen套接字中获取标识符,执行service。只不过这种竞争性的需要给accept加锁

多线程版

创建进程的成本比较大,所以可以适用多线程版本

线程调用的函数来提供service功能,需要传入文件符,ip和port,所以创建一个结构体作为参数。线程执行的routine函数在类内需是静态的,主线程等待线程退出也会阻塞,所以将线程分类,退出信号忽视。静态函数无法调用非静态函数,所以传入的参数内带一个server类变量,向前声明server类,用this指针初始化,用来调用service函数

struct thread_data
{int _fd;string _ip;uint16_t _port;server* ser;
};static void* routine(void* tmp){//线程分离pthread_detach(pthread_self());//可以service函数提到类外//添加一个类成员thread_data *td = static_cast<thread_data*>(tmp);td->ser->service(td->_fd, td->_ip, td->_port);delete td;return nullptr;}pthread_t tid;thread_data* td = new thread_data;td->_fd = sockfd;td->_ip = clientip;td->_port = clientport;td->ser = this;pthread_create(&tid, nullptr, routine, td);

线程池版

多线程版本,如果有一个客户就要建立一个线程,当高峰的时候,可能会有很多个线程同时开启,资源占用大

加入之前写好的线程池,当接收到一个会话后,派给线程池,线程池会自动分配线程执行任务
在这里插入图片描述
修改tash任务类,成员保存文件符,ip和port
在这里插入图片描述
读取内容处理后写回去,关闭文件。常服务不在线程池里跑,执行一次后结束会话
在这里插入图片描述

ThreadPool

#pragma once
#include <vector>
#include <queue>
#include <pthread.h>
#include <string>
#include <unistd.h>//换为封装的线程
struct ThreadInfo
{pthread_t _tid;std::string _name;
};
template <class T>
class pool
{static const int defaultnum = 5;public:std::string getname(pthread_t tid){for (auto ch : _thread){if (ch._tid == tid){return ch._name;}}return "None";}static void* HandlerTask(void* args){pool<T> *tp = static_cast<pool<T> *>(args);std::string name = tp->getname(pthread_self());while (true){pthread_mutex_lock(&(tp->_mutex));while (tp->_que.empty()){pthread_cond_wait(&(tp->_cond), &(tp->_mutex));}T t = tp->_que.front();tp->_que.pop();pthread_mutex_unlock(&tp->_mutex);t.run();//printf("%s finsih task:%s\n", name.c_str(), t.getresult().c_str());//sleep(1);}}void start(){for (int i = 0; i < _thread.size(); i++){_thread[i]._name = "thread" + std::to_string(i);pthread_create(&_thread[i]._tid, nullptr, HandlerTask, this);}}void push(const T& x){pthread_mutex_lock(&_mutex);_que.push(x);pthread_cond_signal(&_cond);pthread_mutex_unlock(&_mutex);}static pool<T>* GetInstance(){//套一层判断,只有第一次需要上锁if (_pl == nullptr){pthread_mutex_lock(&_lock);if (_pl == nullptr){//printf("first create\n");_pl = new pool<T>;}pthread_mutex_unlock(&_lock);}return _pl;}private:
//构造私有化pool(int num = defaultnum): _thread(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}pool(const pool<T> &) = delete;const pool<T> &operator=(const pool<T>&) = delete;~pool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}std::vector<ThreadInfo> _thread;std::queue<T> _que;pthread_mutex_t _mutex;pthread_cond_t _cond;static pthread_mutex_t _lock;static pool<T> *_pl;
};//类外初始化
template <class T>
pool<T>* pool<T>::_pl = nullptr;
template <class T>
pthread_mutex_t pool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;

task

#pragma once
#include <stdio.h>
#include <string>
#include "log.hpp"
#include "init.hpp"// enum
// {
//     DIVZERO = 1,
//     UNKNOW
// };extern Log log;
Dict dict;
struct task
{
public:task(int fd, string ip, uint16_t port){_fd = fd;_ip = ip;_port = port;}void run(){//常服务在线程池跑不合理,循环cout << "welcome " << _ip << endl;char message[1024];ssize_t n = read(_fd, message, sizeof(message) - 1);if (n > 0){message[n] = 0;// 数据处理string echo_string;echo_string = "[" + _ip + ":" + to_string(_port) + "]: " + message;cout << echo_string << endl;write(_fd, echo_string.c_str(), echo_string.size());}else if (n == 0){log.logmessage(info, "quit server");}else{log.logmessage(warning, "read error");}close(_fd);}private:int _fd;string _ip;uint16_t _port;
};

server

#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
//#include <netinet/in.h>
#include <wait.h>
#include <signal.h>
#include "ThreadPool.hpp"
#include "task.hpp"
#include "log.hpp"string defaultip = "0.0.0.0";
uint16_t defaultport = 8000;
const int back = 2;  //连接请求队列个数,一般2-4Log log;enum
{SOCK_ERR = 1,BIND_ERR,LIStEN_ERR
};class server;
struct thread_data
{int _fd;string _ip;uint16_t _port;server* ser;
};class server
{
public:server(const string ip = defaultip, const uint16_t port = defaultport){_ip = defaultip;_port = defaultport;}void init(){_listensock = socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){log.logmessage(fatal, "socket create error");exit(SOCK_ERR);}log.logmessage(info, "socket create success:%d", _listensock);sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;inet_aton(_ip.c_str(), &local.sin_addr);local.sin_port = htons(_port);//绑定if (bind(_listensock, (const struct sockaddr*)&local, sizeof(local)) < 0){log.logmessage(fatal, "bind error:%s",strerror(errno));exit(BIND_ERR);}log.logmessage(info, "bind success");//tcp面向连接,服务器一般被动,处于一种等待连接到来的状态// 设置listen状态if (listen(_listensock, back) < 0){log.logmessage(fatal, "listen error");exit(LIStEN_ERR);}}// void service(int fd, const string ip, const uint16_t port)// {//     cout << "welcome " << ip << endl;//     char message[1024];//     while (true)//     {    //         ssize_t n = read(fd, message, sizeof(message) - 1);//         if (n > 0)//         {//             message[n] = 0;//             //数据处理//             string echo_string;//             echo_string = "[" + ip + ":" + to_string(port) + "]: " + message;//             cout << echo_string << endl;//             write(fd, echo_string.c_str(), echo_string.size());//         }//读到0和其他情况//     }// }// static void* routine(void* tmp)// {//     //线程分离//     pthread_detach(pthread_self());//     //可以service函数提到类外//     //添加一个类成员//     thread_data *td = static_cast<thread_data*>(tmp);//     td->ser->service(td->_fd, td->_ip, td->_port);//     delete td;//     return nullptr;// }void run(){pool<task>::GetInstance()->start();// 忽视子进程//signal(SIGCHLD, SIG_IGN);while (true){//获取链接struct sockaddr_in sock;socklen_t len = sizeof(sock);int sockfd = accept(_listensock, (sockaddr *)&sock, &len);if (sockfd < 0){log.logmessage(warning, "accept fail");continue;}char buff[32];string clientip = inet_ntop(AF_INET, &sock.sin_addr, buff, len);uint16_t clientport = ntohs(sock.sin_port);log.logmessage(info, "get a new link,sockfd:%d", sockfd);// 线程池task t(sockfd, clientip, clientport);pool<task>::GetInstance()->push(t);//多线程// pthread_t tid;// thread_data* td = new thread_data;// td->_fd = sockfd;// td->_ip = clientip;// td->_port = clientport;// td->ser = this;// pthread_create(&tid, nullptr, routine, td);// 多进程// pid_t pid = fork();// if (pid == 0)// {//     // 子进程,孙子进程执行,子进程直接回收//     close(_listensock);//     if (fork() > 0)//         exit(0); // 孙子进程,system领养//     service(sockfd, clientip, clientport);//     close(sockfd);//     exit(0);// }// // 父进程// pid_t ret = waitpid(pid, nullptr, 0);// close(sockfd);}}~server(){close(_listensock);}private:int _listensock;string _ip;uint16_t _port;
};

英汉互译

准备一个词典文件,用:分割单词和汉语
在这里插入图片描述

init类加载词典和提供翻译功能
类成员用unorderedmap,string格式的单词查找存储的string类型汉语值
初始化功能打开文件,分割单词和翻译,加载到数据结构内
在这里插入图片描述

翻译功能遍历map查找翻译

在这里插入图片描述

task文件开始时初始化词典,收到数据调用翻译功能,将结果写会给客户

Dict dict;
echo_string = dict.translate(message);

init.hpp

#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <unordered_map>using namespace std;
const string filename = "./dict.txt";static void split(string line, string* key, string* value)
{auto s = line.find(":");if (s != string::npos){*key = line.substr(0, s);*value = line.substr(s + 1);}
}class Dict
{
public:Dict(){cout << "开始打开" << endl;ifstream dic(filename);if (!dic.is_open()){cout << "file open error" << endl;exit(1);}string line;while (getline(dic, line)){string patr1;string part2;split(line, &patr1, &part2);_dict.insert({patr1, part2});}dic.close();}string translate(string word){for (auto ch : _dict){if (ch.first == word){return ch.second;}}return "";}~Dict(){}
private:unordered_map<string, string> _dict;
};

在这里插入图片描述

错误处理

当客户端发送请求,服务端正在往回写时,客户端的文件已经关闭,往一个不存在的文件写入内容就会发生错误,为了避免这种情况,刚开始的时候先关闭SIGPIP信号
在这里插入图片描述

write函数也有返回值,返回成功写入的字符个数,可以通过返回值判断写入情况
在这里插入图片描述

掉线重连

如果客户端在网络不好等其他情况掉线了,首先需要知道出错,也就是读或者写出错误,需要重新连接,模仿一个重连的情况

重连设置一定次数和时间间隔,用bool变量控制是否需要重连,读取成功后关闭文件重连

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

客户端发送数据的时候,服务端关闭,这时候客户端掉线重连了两次,重启服务端后连接成功

上面的情况有时候可能因为一个端口绑定后无法立即再次绑定,需要调用setsockopt函数复用之前的端口和ip启动

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

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

相关文章

Day28 代码随想录打卡|栈与队列篇---逆波兰表达式求值

题目&#xff08;leecode T150&#xff09;&#xff1a; 给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。每个操作数&#xff08;运算…

机械手避障如何选择激光雷达?

在选择用于机械手避障的激光雷达时&#xff0c;应该考虑以下主要技术参数&#xff1a; 测量范围&#xff1a;激光雷达的测量范围决定了它能够检测到的最大距离。您需要根据机械手的应用场景和工作环境来选择合适的测量范围。 精度&#xff1a;精度是激光雷达测量结果的重要参数…

ENZO--Leptin (human) ELISA kit

瘦素(Leptin)是由ob基因编码、在脂肪组织中生成的一种脂肪代谢调控产物&#xff0c;在代谢和调控体重等方面发挥重要作用。它通过下丘脑中的瘦素受体发出信号&#xff0c;降低食欲&#xff0c;增加能量消耗。在外周组织中&#xff0c;瘦素能拮抗胰岛素信号传导&#xff0c;增加…

Windows只能安装在GPT磁盘上

转换磁盘分区形式 步骤1. 先按照正常流程使用Windows系统安装光盘或系统U盘引导计算机。 步骤2. 在Windows安装程序中点击“开始安装”&#xff0c;然后按ShiftF10打开命令提示符。 步骤3. 依次输入以下命令&#xff0c;并在每一行命令后按一次Enter键执行。 步骤4. 等待转换…

黑马基于Web-socket的java聊天室基本解析

要是用Web-socket协议&#xff0c;我们要前端upgrade升级成web-socket协议 首先我们要引入springboot的websocket起步依赖&#xff0c;这样子方便使用&#xff0c;自己指定版本注意 <dependency><groupId>org.springframework.boot</groupId><artifactId&…

Django视图Views

Views视图 HttpRequest 和HttpResponse Django中的视图主要用来接受web请求&#xff0c;并做出响应。视图的本质就是一个Python中的函数视图的响应分为两大类 1)以Json数据形式返回(JsonResponse) 2)以网页的形式返回 2.1)重定向到另一个网页 (HttpRe…

Mini Cheetah 代码分析(八)基于零空间的任务分级

一、主要公式 二、源代码注释 三、相关原理解释 一、主要公式 二、源代码注释 该功能的实现在文件KinWBC.cpp中的FindConfiguration函数&#xff0c;主要看注释&#xff0c;与公式是能够对应起来的&#xff0c;由第0个任务&#xff0c;也就是接触任务开始进行迭代&#xff0…

Java类和对象(二)—— 封装,static 关键字与代码块

前言 在面向对象的编程语言中&#xff0c;有三大特性&#xff1a;封装、继承和多态~~ 今天我们就来学习封装的知识 封装 什么是封装 在现实生活中&#xff0c;我们经常使用手机来进行沟通与交流&#xff0c;实际上我们拿到的手机是被封装好的&#xff0c;精美的屏幕&a…

关键字详解

1.用于定义访问权限修饰符的关键字 面向对象程序三大特性&#xff1a;封装、继承、多态。 1.1 访问权限符 Java 中主要通过类和访问权限来实现封装&#xff1a; 类可以将数据以及封装数据的方法结合在一起 &#xff0c;更符合人类对事物的认知&#xff0c;而访问权限用来控制…

5月15日,机器人任务挑战赛(无人协同系统)第二期培训即将开启!

一.大赛培训通知 本月起&#xff0c;卓翼飞思实验室将针对机器人任务挑战赛&#xff08;无人协同系统&#xff09;赛项内容开启赛事培训计划&#xff0c;采用“线上线下”相结合的培训模式&#xff0c;围绕赛事关键技术&#xff0c;让您轻松应对比赛。本期培训为第二期&#x…

Go微服务: 日志系统ELK核心架构设计

微服务日志系统建设 1 &#xff09;为什么需要日志系统 业务发展越来越庞大&#xff0c;服务器越来越多各种访问日志&#xff0c;应用日志&#xff0c;错误日志量越来越多&#xff0c;无法管理开发人员排查问题&#xff0c;需要到服务器上查日志 2 &#xff09;Elastic Stack…

惠普打印机无线网络连接设置

休息一下&#xff0c;灌个水。这次没多少内容&#xff0c;具体步骤惠普官网上都有&#xff0c;唯一增加的是对安装过程中踩的坑做了一个说明。 一&#xff0e;打印机无线网络连接设置步骤 惠普打印机设置无线网络连接&#xff0c;共16个步骤。 1. 在电脑上打开任意浏览器&am…

HAProxy系列文章二《Patroni+ETCD+PG14+HAProxy的安装部署》

瀚高数据库 目录 文档用途 详细信息 文档用途 本文主要介绍Patroni架构下单点HAProxy的安装部署&#xff0c;通过单点HAProxy实现数据库的负载均衡。本文为HAProxy系列文章之一&#xff0c;其他相关文章请点击文档下方的相关文档链接进行详细查看&#xff0c;文章内不在赘述。…

Spring MVC(四) 数据校验

在开发过程中有一环必不可少的部分就是数据校验&#xff0c;用户在页面中填写的数据通过表单提交时&#xff0c;前端的JS可以做一些是否合法性的验证&#xff0c;比如是否为空、两次密码是否一致、格式是否正确等等验证。当数据到了后台控制器&#xff0c;为了确保程序的健壮性…

内网环境ubuntu设置静态ip、DNS、路由,不影响网络访问

内网环境通常是有线的&#xff0c;通过服务器的ip、mac、dns地址访问网络才生效的&#xff0c;如果ip地址变了&#xff0c;就不能访问网络了。 如果你的ip地址变了&#xff0c;或者要防止ip变更影响网络访问&#xff0c;就要设置 1、依次点击右上角的电源-设置&#xff0c;在打…

公司里的“卷王”,是主动卷还是迫于无奈?

先来唠唠 “卷” 这个词是近几年流行起来的网络用语&#xff0c;它是内卷的简化形式&#xff0c;“内卷”本来是一个名不见经传的普通词语&#xff0c;经网络流传&#xff0c;很多人就用其来指代非理性的内部竞争或“被自愿”竞争。 在现代职场&#xff0c;有一群人被戏称为&…

三分钟快速上手SpringSecurity框架

导入依赖框架 web 框架(spring-boot-starter-web) <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> springSecurity 框架(spring-boot-starter-security) <de…

基于单片机的空气质量检测系统设计(51+4G版)-设计说明书

设计摘要&#xff1a; 本设计是基于单片机的空气质量检测系统设计涉及以下主要功能&#xff0c;旨在监测甲烷和一氧化碳的浓度&#xff0c;并在浓度过高时采取相应措施&#xff0c;以确保室内空气质量的安全。该系统使用传感器对甲烷和一氧化碳的浓度进行检测。传感器将收集到…

人物介绍模板 PSD 源文件免费获取

免费获取 下载链接在最后&#xff01; 下载链接在最后&#xff01; 下载链接在最后&#xff01; 下载链接在最后&#xff01; 下载链接在最后&#xff01; 链接&#xff1a;https://pan.baidu.com/s/1sq3e6djMdZt76Sh_uqVxWg 提取码&#xff1a;naun

AniPortrait详细讲解以及完整搭建流程(有问题留言)

AniPortrait是一款真实感人像动画的音频驱动合成的AI程序。 下面是它的github源码: GitHub - Zejun-Yang/AniPortrait: AniPortrait: Audio-Driven Synthesis of Photorealistic Portrait AnimationAniPortrait: Audio-Driven Synthesis of Photorealistic Portrait Animati…