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

网络编程套接字,Linux下实现echo服务器和客户端

目录

1、一些网络中的名词

1.1 IP地址

1.2 端口号port

1.3  "端口号" 和 "进程ID"

1.4 初始TCP协议

1.5 UDP协议

2、socket编程接口

2.1 socket 常见API

2.2 sockaddr结构

3、简单的网络程序

3.1 udp实现echo服务器和客户端

3.1.1 echo服务器实现

3.1.2 echo客户端实现

3.1.3 运行结果

3.2  tcp实现echo服务器和客户端

3.2.1 多进程的echo服务器

3.2.2 基于线程池tcp的echo服务器

 3.3 代码中的一些函数

3.3.1 地址转换函数

3.3.2 udp使用的的函数

3.3.3 tcp使用的函数

4、结语


1、一些网络中的名词

1.1 IP地址

        IP地址就和我们现实中的地址是一个概念,只不过一个在网络中定位,一个在现实中定位,

        在一台服务器往另一台服务器发送数据的时候,IP数据包的头部中,有两个IP地址,一个是源IP地址,另一个是目的IP地址,

1.2 端口号port

端口号(port)是传输层协议的内容.

        端口号是一个2字节16位的整数;

        端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;

        IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;

        一个端口号只能被一个进程占用.

1.3  "端口号" 和 "进程ID"

        pid 表示唯一一个进程; 此处我们的端口号也是唯一表示一个进程。一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定。

1.4 初始TCP协议

传输层协议

有连接

可靠传输

面向字节流

1.5 UDP协议

传输层协议

无连接

不可靠传输

面向数据报

网络字节序

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

        发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;

        接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;

        因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.

        TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.

        不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;

        如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;

        为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#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地址转换后准备发送。

如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;

如果主机是大端字节序,这些  函数不做转换,将参数原封不动地返回。

2、socket编程接口

2.1 socket 常见API

// 创建 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);

2.2 sockaddr结构

        socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同.

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

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

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

sockaddr 结构

struct sockaddr{__SOCKADDR_COMMON (sa_);	/* Common data: address family and length.  */char sa_data[14];		/* Address data.  */};

sockaddr_in 结构

struct sockaddr_in{__SOCKADDR_COMMON (sin_);in_port_t sin_port;			/* Port number.  */struct in_addr sin_addr;		/* Internet address.  *//* Pad to size of `struct sockaddr'.  */unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];};

        虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址.

in_addr结构

struct in_addr{in_addr_t s_addr;};

in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数;

3、简单的网络程序

3.1 udp实现echo服务器和客户端

3.1.1 echo服务器实现

//udp_server.hpp
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <unordered_map>
#include <vector>#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>class udpserver{
public:udpserver(std::string ip, int16_t port):_fd(-1), _ip(ip), _port(port),_users(0){}~udpserver(){if (_fd > 0) {close(_fd);}}void initServer() {_fd = socket(AF_INET, SOCK_DGRAM, 0);if (_fd < 0) {perror("注册socket失败");exit(2);}struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = inet_addr(_ip.c_str());if (bind(_fd, (struct sockaddr*)&local, sizeof(local)) < 0) {perror("绑定失败!");exit(3);}//std::cout << "绑定成功!"<< std::endl;}void startServer(){//准备用来接收客户端发送的消息的缓冲区char buffer[1024];while (1) {//准备用来接收发送消息的客户端信息memset(buffer, '\0', sizeof(buffer));struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));socklen_t len = sizeof(peer);//接收数据,以及接收发送数据的客户端信息//std::cout << "正在接收!" << std::endl;ssize_t recv_size = recvfrom(_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);//打印客户端发送来的数据//std::cout << "接收成功!正在打印:" << std::endl;// if (recv_size > 0) {//     buffer[recv_size] = 0;//     std::string ip = inet_ntoa(peer.sin_addr);//     int16_t port = ntohs(peer.sin_port);//     std::cout << "[" << ip << ":" << port << "]:";//     std::cout << buffer << std::endl;// }//处理数据buffer[recv_size] = 0;std::string massage;massage += inet_ntoa(peer.sin_addr);massage += ":";massage += ntohs(peer.sin_port);//_users.insert(make_pair<std::string,struct sockaddr_in>(massage, peer);_users.insert({massage, peer});massage += "#";massage += buffer;//_users.insert(makepair(, peer);//回写数据//sendto(_fd, buffer, strlen(buffer), 0, (struct sockaddr*)&peer, len);for (auto &s : _users) {sendto(_fd, massage.c_str(), massage.size(),0 ,(struct sockaddr*)&(s.second), sizeof(s.second));}}}private:int _fd;std::string _ip;int16_t _port;std::unordered_map<std::string,struct sockaddr_in> _users;
};
//udp_server.cpp
#include "udpserver.hpp"
#include <memory>int main(int argc, char* args[]) {std::string ip;int16_t port = 0;if (argc == 3) {ip = args[1];port = atoi(args[2]);}else if (argc == 2) {ip = "0.0.0.0";port = atoi(args[1]);}else{perror("输入错误!");return 1;}std::unique_ptr<udpserver> server(new udpserver(ip,port));server->initServer();server->startServer();return 0;
}

3.1.2 echo客户端实现

//udp_client.cpp
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include <cstdio>#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>struct sendData{int _sock;struct sockaddr_in *server;
};void* sending(void *arg) {struct sendData* data = (struct sendData*)arg;int sock = data->_sock;struct sockaddr_in server = *(data->server);while (1) {std::string massage;std::cerr << "请输入内容:" ;std::getline(std::cin, massage);//发送数据sendto(sock, massage.c_str(), massage.size(), 0, (struct sockaddr*)&server, sizeof(server));}
}void* receive(void *arg) {struct sendData* data = (struct sendData*)arg;int sock = data->_sock;char buffer[1024];while (1) {memset(buffer, '\0', sizeof(buffer));struct sockaddr_in from;socklen_t len = sizeof(from);ssize_t recv_size = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&from, &len);if(recv_size < 1) {continue;}buffer[recv_size] = '\0';//printf("[%s:%u]#%s\n",inet_ntoa(from.sin_addr),ntohs(from.sin_port),buffer);std::cout << buffer << std::endl;}
}//客户端,负责给服务端发送消息
int main(int argc, char* args[]) {if (argc != 3) {std::cerr << "请正确输入参数!" << std::endl;exit(1);}std::string ip = args[1];int16_t port = atoi(args[2]);//创建套接字int _sock = socket(AF_INET, SOCK_DGRAM, 0);//这里依然会绑定,但是不需要手动绑定,回自动绑定,在第一次send的时候自动绑定,  if (_sock < 0) {exit(2);}struct sockaddr_in server;server.sin_addr.s_addr = inet_addr(ip.c_str());server.sin_family = AF_INET;server.sin_port = htons(port);socklen_t len = sizeof(server);sendData data;data._sock = _sock;data.server = &server;//创建线程,让线程1负责发送,线程2负责接收pthread_t send,recv;pthread_create(&send,nullptr,sending,(void*)&data);pthread_create(&send,nullptr,receive,(void*)&data);pthread_join(send,nullptr);pthread_join(recv,nullptr);close(_sock);return 0;
}

3.1.3 运行结果

3.2  tcp实现echo服务器和客户端

3.2.1 多进程的echo服务器


#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <signal.h>#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>static void servise(int serviseSock, std::string userip, int16_t userport) {char buffer[1024];while (1) {memset(buffer, 0, sizeof(buffer));size_t s = read(serviseSock,buffer,sizeof(buffer));    if (s > 0) {buffer[s] = '\0';std::cout << userip.c_str() << ":" << userport << "#" << buffer << std::endl;}else if (s == 0) {//表示对方关闭了连接std::cerr << userip << ":" << userport << " shutdowm,me too!" << std::endl;break;}else {std::cerr << "read socket error," << errno << strerror(errno) << std::endl;break;}write(serviseSock, buffer, strlen(buffer));}
}class tcpServer{
public:tcpServer(int16_t port, std::string ip = ""):_ip(ip),_port(port),_listenSock(-1){}~tcpServer(){if (_listenSock > 0) {close(_listenSock);}}void initServer(){//backlog不能太大也不能太小static int gbacklog = 20;//申请描述符_listenSock = socket(AF_INET, SOCK_STREAM, 0);if (_listenSock < 0) {std::cerr << "注册socket失败" << std::endl;exit(2);}//绑定端口号和IP地址struct sockaddr_in local;local.sin_family = AF_INET;local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());local.sin_port = htons(_port);if (bind(_listenSock, (struct sockaddr*)&local, sizeof(local)) < 0) {std::cerr << "绑定ip和端口号失败" << std::endl;exit(3);}//设置监听状态if (listen(_listenSock, gbacklog) < 0) {std::cerr << "设置监听失败" << std::endl;exit(4);}}void start() {//将子进程的信号改为忽略signal(SIGCHLD, SIG_IGN);while (1) {struct sockaddr_in user;socklen_t len = sizeof(user);int serviseSock = accept(_listenSock, (struct sockaddr*)&user, &len);std::string userip = inet_ntoa(user.sin_addr);int16_t userport = ntohs(user.sin_port);//servise(serviseSock,userip,userport);int pid = fork();if (pid == 0) {close(_listenSock);servise(serviseSock,userip,userport);close(serviseSock);exit(0);}close(serviseSock);}}private:std::string _ip;int16_t _port;int _listenSock;
};

        但是我们都知道,在操作系统中,进程是资源分配的基本单位,如果使用多进程的方案的话,就非常的浪费资源,所以,相比之下,使用多线程的方式回更好,我们在实现一个基于线程池的实现方式。

3.2.2 基于线程池tcp的echo服务器

//自己实现的循环队列,当中使用的锁和信号都是自己封装的,这里就不放代码了
//ringqueue.hpp
#include <iostream>
#include <vector>
#include "sem.hpp"
#include "mutex.hpp"template<class T>
class ringqueue {public:ringqueue(int capacity = 10):_ring_queue(capacity),_start(0),_tail(0),_space_sem(capacity),_data_sem(0),_mtx(){}void push(const T &in){_space_sem.p();_mtx.lock();_ring_queue[_start++] = in;_start %= _ring_queue.size();_data_sem.v();_mtx.unlock();}void pop(T & out){_data_sem.p();_mtx.lock();out = _ring_queue[_tail++];_tail %= _ring_queue.size();_space_sem.v();_mtx.unlock();}~ringqueue(){}private:std::vector<T> _ring_queue;int _start;int _tail;sem _space_sem;sem _data_sem;mutex _mtx;
};
//单例模式的线程池
//其中的线程也是自己进行封装的,不做代码展示
//thread_pool.hpp
#include "thread.hpp"
#include "ringQueue.hpp"
#include <ctime>
#include <unistd.h>template <class T>
struct poolData
{Thread* _self;ringqueue<T>* _rq;
};template <class T>
class Pool
{public:static Pool<T>* getpool(int num = 10){if (nullptr == _pool) {pthread_mutex_lock(&mtx);if (nullptr == _pool) {_pool = new Pool<T>(num);}pthread_mutex_unlock(&mtx);}return _pool;}private:Pool(int num) :_consumer(num),_rq(10){}Pool(const Pool& pool) = delete;Pool& operator=(const Pool& pool) = delete;
public:void strat(){poolData<T> condata[_consumer.size()];for (int i = 0; i < _consumer.size(); ++i) {_consumer[i] = new Thread(i);condata[i]._self = _consumer[i];condata[i]._rq = &_rq;_consumer[i]->create(consumer,&condata[i]);}}// 生产者void pushTask(T task){_rq.push(task);}// 消费者static void *consumer(void *args){poolData<T> *pd = (poolData<T>*)args;Thread *self = pd->_self;ringqueue<T> *rq = pd->_rq;std::cout << self->name() << " Successfully started!" << std::endl;while (true) {T t;rq->pop(t);(*t)();delete t;}}~Pool(){for (int i = 0; i < _consumer.size(); ++i) {_consumer[i]->join();delete _consumer[i];}}private:ringqueue<T> _rq;std::vector<Thread*> _consumer;static pthread_mutex_t mtx;static Pool<T>* _pool;
};template<class T>
Pool<T>* Pool<T>::_pool = nullptr;template<class T>
pthread_mutex_t Pool<T>::mtx = PTHREAD_MUTEX_INITIALIZER;
//tcp_server.hpp
#include "thread_pool.hpp"
#include "Task.hpp"#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <signal.h>#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>static void servise(int serviseSock, std::string & userip, int16_t userport) {char buffer[1024];while (1) {memset(buffer, 0, sizeof(buffer));size_t s = read(serviseSock,buffer,sizeof(buffer));    if (s > 0) {buffer[s] = '\0';std::cout << userip.c_str() << ":" << userport << "#" << buffer << std::endl;}else if (s == 0) {//表示对方关闭了连接std::cerr << userip << ":" << userport << " shutdowm,me too!" << std::endl;break;}else {std::cerr << "read socket error," << errno << strerror(errno) << std::endl;break;}write(serviseSock, buffer, strlen(buffer));}close(serviseSock);
}class tcpServer{
public:tcpServer(int16_t port, std::string ip = ""):_ip(ip),_port(port),_listenSock(-1),_pool_ptr(Pool<Task*>::getpool()){}~tcpServer(){if (_listenSock > 0) {close(_listenSock);}}void initServer(){//backlog不能太大也不能太小static int gbacklog = 20;//申请描述符_listenSock = socket(AF_INET, SOCK_STREAM, 0);if (_listenSock < 0) {std::cerr << "注册socket失败" << std::endl;exit(2);}//绑定端口号和IP地址struct sockaddr_in local;local.sin_family = AF_INET;local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());local.sin_port = htons(_port);if (bind(_listenSock, (struct sockaddr*)&local, sizeof(local)) < 0) {std::cerr << "绑定ip和端口号失败" << std::endl;exit(3);}//设置监听状态if (listen(_listenSock, gbacklog) < 0) {std::cerr << "设置监听失败" << std::endl;exit(4);}}void start() {_pool_ptr->strat();while (1) {struct sockaddr_in user;socklen_t len = sizeof(user);int serviseSock = accept(_listenSock, (struct sockaddr*)&user, &len);std::string userip = inet_ntoa(user.sin_addr);int16_t userport = ntohs(user.sin_port);Task *task = new Task(serviseSock, userip, userport, servise);_pool_ptr->pushTask(task);}}private:std::string _ip;int16_t _port;int _listenSock;Pool<Task*>* _pool_ptr;
};
//服务器入口,
//tcp_server.cpp
#include "tcp_server.hpp"
#include <memory>int main(int argc, char* args[]) {std::string ip;int16_t port;if (argc == 2) {ip = "";port = atoi(args[1]);}else if (argc == 3) {ip = args[1];port = atoi(args[2]);}else {std::cerr << "输入错误!" << std::endl;exit(1);}std::unique_ptr<tcpServer> server(new tcpServer(port,ip));server->initServer();server->start();return 0;
}

3.2.3 运行结果

 3.3 代码中的一些函数

3.3.1 地址转换函数

        本节基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位  的IP 地址但是我们通常用点分十进制的字符串表示IP 地址,以下函数可以在字符串表示  和in_addr表示之间转换;

字符串与in_addr的一些函数:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
in_addr_t inet_network(const char *cp);
char *inet_ntoa(struct in_addr in);
struct in_addr inet_makeaddr(int net, int host);
in_addr_t inet_lnaof(struct in_addr in);
in_addr_t inet_netof(struct in_addr in);

3.3.2 udp使用的的函数

发送函数sendto:

#include <sys/types.h>
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

接收函数recvfrom:

#include <sys/types.h>
#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

3.3.3 tcp使用的函数

发送函数

#include <sys/types.h>
#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);

接收函数

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
#include <sys/types.h>
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);

4、结语

        本文中若有错误,请私信或评论指出,谢谢!

相关文章:

网络编程套接字,Linux下实现echo服务器和客户端

目录 1、一些网络中的名词 1.1 IP地址 1.2 端口号port 1.3 "端口号" 和 "进程ID" 1.4 初始TCP协议 1.5 UDP协议 2、socket编程接口 2.1 socket 常见API 2.2 sockaddr结构 3、简单的网络程序 3.1 udp实现echo服务器和客户端 3.1.1 echo服务器实…...

java+ssh+mysql智能化办公管理系统

项目介绍&#xff1a; 本系统为基于jspsshmysql的OA智能办公管理系统&#xff0c;包含管理员、领导、员工角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;公告信息&#xff1b;工作计划&#xff1b;公司资料&#xff1b;部门管理&#xff1b;员工管理&#xff1b;员…...

网络层抓包tcpdump

sudo tcpdump -i eth0 -s 0 -nn host iphost -w xxx.pcap 这段代码使用了命令行工具 tcpdump&#xff0c;用于在Linux系统上捕获网络数据包。让我详细介绍一下这段代码的含义和 tcpdump 的用法&#xff1a; 代码含义&#xff1a; sudo: 使用超级用户权限执行 tcpdump 命令&am…...

QT之形态学操作

形态学操作包含以下操作&#xff1a; 腐蚀 (Erosion)膨胀 (Dilation)开运算 (Opening)闭运算 (Closing)形态梯度 (Morphological Gradient)顶帽 (Top Hat)黑帽(Black Hat) 其中腐蚀和膨胀操作是最基本的操作&#xff0c;其他操作由这两个操作变换而来。 腐蚀 用一个结构元素…...

15、监测数据采集物联网应用开发步骤(11)

源码将于最后一遍文章给出下载 监测数据采集物联网应用开发步骤(10) 程序自动更新开发 前面章节写了部分功能模块开发&#xff1a; 日志或文本文件读写开发;Sqlite3数据库读写操作开发;定时器插件化开发;串口(COM)通讯开发;TCP/IP Client开发;TCP/IP Server 开发;modbus协议…...

Pygame中Trivia游戏解析6-2

3.1.2 读取保存题目的文件 在Trivia类的__init__()方法中&#xff0c;对各变量初始化完成之后&#xff0c;读取保存题目的文件&#xff0c;代码如下所示。 f open(filename, "r", encodingutf8) trivia_data f.readlines() f.close() 其中&#xff0c;open()函数…...

java 实现命令行模式

命令模式是一种行为设计模式&#xff0c;它允许您将请求封装为对象&#xff0c;以便您可以将其参数化、队列化、记录和撤销。在 Java 中实现命令模式涉及创建一个命令接口&#xff0c;具体命令类&#xff0c;以及一个接收者类&#xff0c;该接收者类执行实际操作。下面是一个简…...

A - Orac and Models(最长上升子序列——加强版)

There are nn models in the shop numbered from 11 to nn, with sizes s_1, s_2, \ldots, s_ns1​,s2​,…,sn​. Orac will buy some of the models and will arrange them in the order of increasing numbers (i.e. indices, but not sizes). Orac thinks that the obtai…...

【python手写算法】逻辑回归实现分类(含公式推导)

公式推导&#xff1a; 代码实现&#xff1a; # codingutf-8 import matplotlib.pyplot as plt import numpy as npdef f(w1,x1,w2,x2,b):zw1*x1w2*x2breturn 1/(1np.exp(-z)) if __name__ __main__:X1 [12.46, 0.25, 5.22, 11.3, 6.81, 4.59, 0.66, 14.53, 15.49, 14.43,2.1…...

【2023高教社杯数学建模国赛】ABCD题 问题分析、模型建立、参考文献及实现代码

【2023高教社杯数学建模国赛】ABCD题 问题分析、模型建立、参考文献及实现代码 1 比赛时间 北京时间&#xff1a;2023年9月7日 18:00-2023年9月10日20:00 2 思路内容 可以参考我提供的历史竞赛信息内容&#xff0c;最新更新我会发布在博客和知乎上&#xff0c;请关注我获得最…...

yum安装mysql5.7散记

## 数据源安装 $ yum -y install wget $ wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm $ yum localinstall mysql57-community-release-el7-8.noarch.rpm $ yum repolist enabled | grep "mysql.*-community.*" $ yum install mysql-…...

DNS解析

1.DNS介绍 DNS 表示域名系统。此系统实质上是用于整理和识别各个域名的网络电话簿。电话簿将“Acme Pizza”之类的名称转换为要拨打的正确电话号码&#xff0c;而 DNS 将“www.google.com”之类的网络地址转换为托管该网站的计算机的物理 IP 地址&#xff0c;如“74.125.19.147…...

从jdk8 升级到jdk17的问题总结

目录 1. java.lang.reflect.InaccessibleObjectException: 2. java.lang.UnsatisfiedLinkError in autosys 3. java.lang.NoClassDefFoundError: Could not initialize class net.sf.jasperreports.engine.util.JRStyledTextParser 4. java.lang.UnsatisfiedLinkError: **…...

一百七十二、Flume——Flume采集Kafka数据写入HDFS中(亲测有效、附截图)

一、目的 作为日志采集工具Flume&#xff0c;它在项目中最常见的就是采集Kafka中的数据然后写入HDFS或者HBase中&#xff0c;这里就是用flume采集Kafka的数据导入HDFS中 二、各工具版本 &#xff08;一&#xff09;Kafka kafka_2.13-3.0.0.tgz &#xff08;二&#xff09;…...

pnpm 升级

1. 在以下路径下删除pnpm包 2. 执行which pnpm&#xff0c;在结果目录中删除pnpm 3. sudo npm install -g pnpm 重新安装&#xff0c;node默认使用16...

有关使用HttpServletRequest的Cookie的设置和获取

文章目录 小结问题和解决参考 小结 介绍了如何在HttpServletRequest中对Cookie的进行设置和获取。 问题和解决 在服务器端的HttpServletRequest中对Cookie的进行设置后&#xff0c;客户端在接下来的请求中会携带此设置好的Cookie&#xff0c;所以可以在服务器端接收请求时提…...

关于 Nginx 的哪些事

关于 Nginx 的哪些事 1、Nginx 主要功能2、Nginx 的常用命令2.1、启动Nginx2.2、停止 Nginx2.3、重新加载Nginx 配置2.4、检查Nginx配置文件2.5、指定配置文件2.6、检查Nginx版本2.7、显示Nginx帮助信息 3、Nginx 配置文件 nginx.conf3.1、Nginx 配置文件&#xff08;nginx.con…...

插入排序——希尔排序

1、简述&#xff1a; 希尔排序(Shells Sort)是插入排序的一种又称“缩小增量排序”&#xff08;Diminishing Increment Sort&#xff09;&#xff0c;是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。 希尔排…...

C语言之初阶总结篇

目录 NO.1 NO.2 NO.3 NO.4 NO.5 NO.6 NO.7 NO.8 NO.9 NO.10 NO.11 NO.12.概念tips NO.13.求最小公倍数 NO.14.最大公因数 NO.15.输入读取字符串 NO.16.倒置字符串 今天是一些C语言题目&#xff0c;最近天气炎热&#xff0c;多喝水。 NO.1 下面程序执行后&am…...

Android签名查看

查看签名文件信息 第一种方法&#xff1a; 1.打开cmd&#xff0c;执行keytool -list -v -keystore xxx.keystore&#xff0c;效果如下图&#xff1a; 第二种方法: 1.打开cmd&#xff0c;执行 keytool -list -v -keystore xxxx.keystore -storepass 签名文件密码&#xff0…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...