当前位置: 首页 > 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…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

WEB3全栈开发——面试专业技能点P7前端与链上集成

一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染&#xff08;SSR&#xff09;与静态网站生成&#xff08;SSG&#xff09; 框架&#xff0c;由 Vercel 开发。它简化了构建生产级 React 应用的过程&#xff0c;并内置了很多特性&#xff1a; ✅ 文件系…...