网络编程套接字,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智能化办公管理系统
项目介绍: 本系统为基于jspsshmysql的OA智能办公管理系统,包含管理员、领导、员工角色,功能如下: 管理员:公告信息;工作计划;公司资料;部门管理;员工管理;员…...
网络层抓包tcpdump
sudo tcpdump -i eth0 -s 0 -nn host iphost -w xxx.pcap 这段代码使用了命令行工具 tcpdump,用于在Linux系统上捕获网络数据包。让我详细介绍一下这段代码的含义和 tcpdump 的用法: 代码含义: sudo: 使用超级用户权限执行 tcpdump 命令&am…...
QT之形态学操作
形态学操作包含以下操作: 腐蚀 (Erosion)膨胀 (Dilation)开运算 (Opening)闭运算 (Closing)形态梯度 (Morphological Gradient)顶帽 (Top Hat)黑帽(Black Hat) 其中腐蚀和膨胀操作是最基本的操作,其他操作由这两个操作变换而来。 腐蚀 用一个结构元素…...
15、监测数据采集物联网应用开发步骤(11)
源码将于最后一遍文章给出下载 监测数据采集物联网应用开发步骤(10) 程序自动更新开发 前面章节写了部分功能模块开发: 日志或文本文件读写开发;Sqlite3数据库读写操作开发;定时器插件化开发;串口(COM)通讯开发;TCP/IP Client开发;TCP/IP Server 开发;modbus协议…...
Pygame中Trivia游戏解析6-2
3.1.2 读取保存题目的文件 在Trivia类的__init__()方法中,对各变量初始化完成之后,读取保存题目的文件,代码如下所示。 f open(filename, "r", encodingutf8) trivia_data f.readlines() f.close() 其中,open()函数…...
java 实现命令行模式
命令模式是一种行为设计模式,它允许您将请求封装为对象,以便您可以将其参数化、队列化、记录和撤销。在 Java 中实现命令模式涉及创建一个命令接口,具体命令类,以及一个接收者类,该接收者类执行实际操作。下面是一个简…...
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手写算法】逻辑回归实现分类(含公式推导)
公式推导: 代码实现: # 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 比赛时间 北京时间:2023年9月7日 18:00-2023年9月10日20:00 2 思路内容 可以参考我提供的历史竞赛信息内容,最新更新我会发布在博客和知乎上,请关注我获得最…...
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”之类的名称转换为要拨打的正确电话号码,而 DNS 将“www.google.com”之类的网络地址转换为托管该网站的计算机的物理 IP 地址,如“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,它在项目中最常见的就是采集Kafka中的数据然后写入HDFS或者HBase中,这里就是用flume采集Kafka的数据导入HDFS中 二、各工具版本 (一)Kafka kafka_2.13-3.0.0.tgz (二)…...
pnpm 升级
1. 在以下路径下删除pnpm包 2. 执行which pnpm,在结果目录中删除pnpm 3. sudo npm install -g pnpm 重新安装,node默认使用16...
有关使用HttpServletRequest的Cookie的设置和获取
文章目录 小结问题和解决参考 小结 介绍了如何在HttpServletRequest中对Cookie的进行设置和获取。 问题和解决 在服务器端的HttpServletRequest中对Cookie的进行设置后,客户端在接下来的请求中会携带此设置好的Cookie,所以可以在服务器端接收请求时提…...
关于 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 配置文件(nginx.con…...
插入排序——希尔排序
1、简述: 希尔排序(Shells Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 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语言题目,最近天气炎热,多喝水。 NO.1 下面程序执行后&am…...
Android签名查看
查看签名文件信息 第一种方法: 1.打开cmd,执行keytool -list -v -keystore xxx.keystore,效果如下图: 第二种方法: 1.打开cmd,执行 keytool -list -v -keystore xxxx.keystore -storepass 签名文件密码࿰…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果。链条循环: Bean A → Bean…...
