C++ 实现Socket交互式服务端

在 Windows 操作系统中,原生提供了强大的网络编程支持,允许开发者使用 Socket API 进行网络通信,通过 Socket API,开发者可以创建、连接、发送和接收数据,实现网络通信。本文将深入探讨如何通过调用原生网络 API 实现同步远程通信,并介绍了一个交互式 Socket 类的封装,提升了编写交互式服务器的便利性。

1. 交互式套接字类

为了更好地利用原生网络 API,我们引入了一个交互式 Socket 类的封装。这个类抽象了底层的网络细节,提供了简单而强大的接口,使得服务器端的交互式功能更容易实现。我们将详细介绍这个类的设计和使用方法。

MySocket 类是一个 C++ 套接字类,封装了在 Windows 平台上使用原生网络 API 进行同步远程通信的基本功能,该类需要使用多字节编码模式,服务端与客户端均需要引入此类,在项目头文件中均需要新建MySocket.hpp文件。

粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

完整代码如下所示;

#pragma once
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")class MySocket
{
protected:SOCKET m_hSocket;
public:// 获取对端Socket用户IP端口等BOOL GetPeerName(char* rSocketAddress, UINT& rSocketPort){sockaddr_in name = { AF_INET };int lenname = sizeof(name);if (getpeername(m_hSocket, (sockaddr*)&name, &lenname) < 0)return false;strcpy(rSocketAddress, inet_ntoa(name.sin_addr));rSocketPort = htons(name.sin_port);return true;}// 获取本机Socket用户IP端口等BOOL GetSockName(char* rSocketAddress, UINT& rSocketPort){sockaddr_in name = { AF_INET };int lenname = sizeof(name);if (getsockname(m_hSocket, (sockaddr*)&name, &lenname) < 0)return false;strcpy(rSocketAddress, inet_ntoa(name.sin_addr));rSocketPort = htons(name.sin_port);return true;}// 获取当前用户SocketIDBOOL GetSocketID(){return m_hSocket;}// 创建套接字BOOL Create(UINT nSocketPort = 0, int nSockType = SOCK_STREAM, LPCTSTR lpszSocketAddress = NULL){// 创建套接字m_hSocket = socket(AF_INET, nSockType, 0);if (m_hSocket == INVALID_SOCKET)return false;// 设置IP地址和端口sockaddr_in sa = { AF_INET };sa.sin_port = htons(nSocketPort);if (lpszSocketAddress)sa.sin_addr.s_addr = inet_addr(lpszSocketAddress);// 绑定套接字和IP地址端口return !bind(m_hSocket, (sockaddr*)&sa, sizeof(sa));}// 接受客户请求BOOL Accept(MySocket& rConnectedSock, LPSTR szIp = NULL, UINT* nPort = NULL){sockaddr_in sa = { AF_INET };int nLen = sizeof(sa);rConnectedSock.m_hSocket = accept(this->m_hSocket, (sockaddr*)&sa, &nLen);if (rConnectedSock.m_hSocket == INVALID_SOCKET)return false;if (szIp)strcpy(szIp, inet_ntoa(sa.sin_addr));if (nPort)*nPort = htons(sa.sin_port);return true;}// 连接服务端BOOL Connection(LPCSTR lpszHostAddress, UINT nPort){sockaddr_in sa = { AF_INET };sa.sin_port = htons(nPort);sa.sin_addr.s_addr = inet_addr(lpszHostAddress);return !connect(m_hSocket, (sockaddr*)&sa, sizeof(sa));}// 侦听BOOL Listen(int nConnectionBacklog = 5){return !listen(m_hSocket, nConnectionBacklog);}// 逐条发送int Send(const void* lpBuf, int nBufLen, int nFlags = 0){return send(m_hSocket, (LPCSTR)lpBuf, nBufLen, nFlags);}// 发送整个缓冲区int SendTo(const void* lpBuf, int nBufLen, UINT nHostPort, LPCSTR lpszHostAddress = NULL,int nFlags = 0){sockaddr_in to = { AF_INET };to.sin_port = htons(nHostPort);to.sin_addr.s_addr = inet_addr(lpszHostAddress);return sendto(m_hSocket, (LPCSTR)lpBuf, nBufLen, nFlags, (sockaddr*)&to, sizeof(to));}// 逐条接收int Receive(void* lpBuf, int nBufLen, int nFlags = 0){return recv(m_hSocket, (LPTSTR)lpBuf, nBufLen, nFlags);}// 接收整个缓冲区int ReceiveFrom(void* lpBuf, int nBufLen, char* rSocketAddress, UINT& rSocketPort, int nFlags = 0){sockaddr_in from = { AF_INET };int lenFrom = sizeof(from);int n = recvfrom(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags, (sockaddr*)&from, &lenFrom);strcpy(rSocketAddress, inet_ntoa(from.sin_addr));rSocketPort = htons(from.sin_port);return n;}// 关闭套接字void Close(){closesocket(m_hSocket);m_hSocket = INVALID_SOCKET;}MySocket(){WSADATA wsaData;WSAStartup(0x0202, &wsaData);m_hSocket = INVALID_SOCKET;}~MySocket(){Close();}
};

以下是对该类的概括:

类名:MySocket

功能:提供了基本的网络通信功能,包括创建套接字、获取对端和本机的信息、接受客户端连接、连接服务端、监听连接请求、发送和接收数据。

成员变量:

SOCKET m_hSocket:套接字句柄,用于标识一个套接字。

成员函数:

Create:创建套接字,并可指定类型、本地端口和地址。

Accept:接受客户请求,返回连接的套接字。

Connection:连接到服务端。

Listen:开始监听连接请求。

Send:逐条发送数据。

SendTo:发送整个缓冲区到指定地址。

Receive:逐条接收数据。

ReceiveFrom:接收整个缓冲区,并获取发送端地址和端口。

Close:关闭套接字。

初始化和清理:

构造函数 MySocket:初始化 Winsock 库和套接字句柄。

析构函数 ~MySocket:关闭套接字。

使用注意事项:

适用于简单的同步网络通信场景。

该类提供了一些基本的网络编程功能,适合用于创建简单的服务器端和客户端。需注意,这是一个同步实现的套接字类,适用于一些较为简单的网络通信需求。

2. 实现简单的通信

通过具体的代码示例,我们将演示如何使用交互式 Socket 类在 Windows 操作系统上实现同步远程通信。代码将包括服务器端和客户端的实现,以及它们之间的交互过程。通过这些示例,读者将更好地理解如何在实际项目中应用这些概念。

2.1 服务端流程

如下代码是一个简单的服务端程序,通过 MySocket 类建立基于 TCP 协议的服务器,通过sock.Create()创建套接字,然后通过sock.Accept()接收套接字,当有新的套接字连入时自动调用_beginthread()函数开启一个子线程维持套接字的运行,每一个子线程内部则都由ClientPro()函数来实现交互。

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include <iostream>
#include <process.h>
#include "MySocket.hpp"using namespace std;void ClientPro(void* ptr)
{// 初始化MySocket* pSock = (MySocket*)ptr;MySocket server_socket = *pSock;server_socket.Send((const char *)"Welcome to LyServer", 19);// 获取客户端信息char sIp[20];UINT nPort;server_socket.GetPeerName(sIp, nPort);while (true){char szBuffer[4096] = { 0 };// 接收客户返回消息int ref = server_socket.Receive(szBuffer, sizeof(szBuffer));if (ref <= 0){std::cout << "客户: " << sIp << ":" << nPort << " [已断开]" << std::endl;break;}std::cout << "地址: " << sIp << ":" << nPort << " 接收命令: " << szBuffer << std::endl;// 选择不同的命令if (strcmp(szBuffer, "list\n") == 0){std::cout << "输出文件" << std::endl;}else if (strcmp(szBuffer, "download\n") == 0){std::cout << "下载文件" << std::endl;}else if (strcmp(szBuffer, "upload\n") == 0){std::cout << "上传文件" << std::endl;}// 返回给客户端server_socket.Send((char*)"ok", 2);}
}int main(int argc, char *argv[])
{MySocket sock;if (!sock.Create(8233, SOCK_STREAM, "127.0.0.1")){return -1;}// 获取本机信息char sSevIp[20];UINT nSevPort;sock.GetSockName(sSevIp, nSevPort);std::cout << "服务端: " << sSevIp << ":" << nSevPort << " 服务器启动成功" << std::endl;sock.Listen(5);// 获取客户端信息char sIp[20];UINT nPort;MySocket ptr;while (true){// 当有新用户进来自动创建一个线程来维持会话sock.Accept(ptr, sIp, &nPort);std::cout << "客户: " << sIp << ":" << nPort << " [已登录]" << std::endl;// 多线程_beginthread(ClientPro, 0, &ptr);}return 0;
}

以下是对该代码的概括:

功能:实现一个简单的基于 TCP 的服务器,监听指定端口(8233),接受客户端连接,创建一个线程处理每个客户端的会话。

主要函数和过程:

ClientPro 函数:处理每个客户端的会话。向客户端发送欢迎消息,接收客户端发送的命令,根据不同的命令执行相应的操作,并向客户端发送响应。该函数通过多线程在后台运行,使得服务器能够同时处理多个客户端。

main 函数:在主线程中创建 MySocket 类实例 sock,并调用 Create 函数创建服务器套接字。然后,通过 Listen 函数监听客户端连接。在循环中,通过 Accept 函数接受客户端连接,并为每个客户端创建一个新线程,用于处理客户端的会话。

通信协议:客户端和服务器之间通过简单的文本协议进行通信。客户端发送不同的命令(“list”、“download”、“upload”),服务器接收命令并执行相应的操作,然后向客户端发送响应(“ok”)。

线程创建:使用 _beginthread 函数在每个新连接上创建一个线程,用于处理该客户端的会话。

2.2 客户端流程

如下代码是一个简单的客户端程序,通过 MySocket 类实现与服务端的基于 TCP 协议的通信,通过sock.Connection()建立套接字链接,通过sock.Receive()接收数据,通过sock.Send()发送数据,其运行原理与原生套接字写法保持一致。

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include "MySocket.hpp"using namespace std;int main(int argc, char* argv[])
{MySocket sock;if (!sock.Create(0, SOCK_STREAM)){return -1;}// 获取本机信息char sClientIp[20];UINT nClientPort;sock.GetSockName(sClientIp, nClientPort);std::cout << "服务端: " << sClientIp << ":" << nClientPort << " 服务器启动成功" << std::endl;if (!sock.Connection("127.0.0.1", 8233)){cout << "连接服务器失败" << GetLastError() << endl;return -1;}char szBuffer[4096] = { 0 };int ref = sock.Receive(szBuffer, sizeof(szBuffer));szBuffer[ref] = 0;std::cout << "服务端回应: " << szBuffer << std::endl;while (true){// 循环接受输入input:memset(szBuffer, 0, 4096);std::cout << "Input CMD > ";// 接收输入命令int inputLine = 0;while ((szBuffer[inputLine++] = getchar()) != '\n');if (strlen(szBuffer) == 1)goto input;// 发送数据sock.Send(szBuffer, 4096, 0);// 接收回显memset(szBuffer, 0, 4096);sock.Receive(szBuffer, 4096, 0);std::cout << "服务端回显: " << szBuffer << std::endl;}sock.Close();return 0;
}

以下是对该代码的概括:

功能:实现一个基于 TCP 的客户端,连接到指定 IP 地址和端口(127.0.0.1:8233),与服务器建立连接后,可以输入命令并发送到服务器,接收并显示服务器的回显。

主要函数和过程:

main 函数:在主线程中创建 MySocket 类实例 sock,并调用 Create 函数创建客户端套接字。然后,通过 Connection 函数连接到服务器。接着,通过 Receive 函数接收服务器发送的欢迎消息,并显示在控制台。

在一个无限循环中,通过标准输入接收用户输入的命令,将命令发送到服务器,然后接收并显示服务器的回显。

通信协议:客户端和服务器之间通过简单的文本协议进行通信。客户端发送用户输入的命令,服务器执行命令并将结果回显给客户端。

输入循环:通过一个无限循环,不断接收用户输入的命令,并发送到服务器。如果用户输入空命令,程序会跳转回 input 标签重新接收输入。

错误处理:在连接服务器失败时,通过 GetLastError() 输出详细错误信息。

关闭套接字:在程序结束时,通过 sock.Close() 关闭套接字。

依次运行服务端和客户端,然后当客户端连接成功后此时的服务端即可收到连接请求,此时客户端可以执行各类简单的命令,如下图所示;

3.实现登录服务器

上述代码只是一个简单的演示案例,用来演示如何使用套接字编写交互程序,如下我们将继续完善这段代码,实现一个简单的带有登录功能的登录服务器程序,使用户可以在执行命令前具备简单的登录认证功能。

3.1 服务端流程

如下代码是一个简单的基于 Windows 的多线程服务器程序,通过 MySocket 类实现与客户端的基于 TCP 协议的通信,在交互模式下用户可输入多种命令,登录登出以及登陆后的命令执行功能。

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include <iostream>
#include <process.h>
#include <vector>
#include "MySocket.hpp"using namespace std;// 登录状态记录
typedef struct
{char UserName[32];int SocketID;
}loginPool;// ------------------------------------------------------------------------
// 用户登录验证代码部分std::vector<loginPool> login_pool_vect;// 检查用户ID是否存在与容器内,如果存在则返回用户名
bool is_login(std::vector<loginPool> &ptr, int socket_id)
{for (int x = 0; x < ptr.size(); x++){if (ptr[x].SocketID == socket_id){return true;}}return false;
}// 用户登录验证
bool login(char *username, char *password, int socket_id)
{if ((strcmp(username, "lyshark") == 0) && (strcmp(password, "123123") == 0)){// 如果在则增加一个socket登录标志loginPool pool_ptr;pool_ptr.SocketID = socket_id;strcpy(pool_ptr.UserName, "lyshark");login_pool_vect.push_back(pool_ptr);return true;}else if ((strcmp(username, "admin") == 0) && (strcmp(password, "123456") == 0)){// 如果在则增加一个socket登录标志loginPool pool_ptr;pool_ptr.SocketID = socket_id;strcpy(pool_ptr.UserName, "lyshark");login_pool_vect.push_back(pool_ptr);return true;}return false;
}// 根据传入ID从容器内弹出一个节点
bool logout(std::vector<loginPool> &ptr, int socket_id)
{for (vector<loginPool>::iterator it = ptr.begin(); it != ptr.end(); it++){if (it->SocketID == socket_id){// 弹出指定结构体ptr.erase(it);return true;}}return false;
}// ------------------------------------------------------------------------
// 响应客户端的子线程(主要功能实现部分)
void ClientPro(void* ptr)
{// 初始化MySocket* pSock = (MySocket*)ptr;MySocket server_socket = *pSock;server_socket.Send((const char *)"Welcome to LyShark Mini Server", 31);// 获取客户端信息char sIp[20];UINT nPort;server_socket.GetPeerName(sIp, nPort);while (true){char szBuffer[4096] = { 0 };int sid = pSock->GetSocketID();int ref = server_socket.Receive(szBuffer, sizeof(szBuffer));if (ref <= 0){logout(login_pool_vect, sid);std::cout << "客户: " << sIp << ":" << nPort << " [已断开]" << std::endl;break;}std::cout << "地址: " << sIp << ":" << nPort << " 接收命令: " << szBuffer << std::endl;// 用户登录if (strcmp(szBuffer, "login\n") == 0){char recv_username[32] = { 0 };char recv_password[32] = { 0 };// 接收用户名和密码pSock->Receive(recv_username, 32, 0);pSock->Receive(recv_password, 32, 0);// 验证登录状态bool login_flag = login(recv_username, recv_password, sid);if (login_flag == TRUE){std::cout << "用户: " << recv_username << " 已登录" << std::endl;pSock->Send("已登录", sizeof("已登录"), 0);}else{pSock->Send("账号或密码错误", sizeof("账号或密码错误"), 0);}}// 用户登出else if (strcmp(szBuffer, "logout\n") == 0){// 验证是否登录成功int login_flag = is_login(login_pool_vect, sid);if (login_flag == TRUE){std::cout << "用户已登出" << std::endl;logout(login_pool_vect, sid);pSock->Send("用户已登出", sizeof("用户已登出"), 0);}else{std::cout << "请先登录" << std::endl;pSock->Send("请先登录", sizeof("请先登录"), 0);}}// 遍历本机文件else if (strcmp(szBuffer, "list\n") == 0){// 验证是否登录成功int login_flag = is_login(login_pool_vect, sid);if (login_flag == TRUE){std::cout << "用户已登录,输出本机文件" << std::endl;pSock->Send("认证通过", sizeof("认证通过"), 0);// 循环输出数据包for (int x = 0; x < 10; x++){char sz[1024] = { 0 };sprintf(sz, "count -> %d", x);pSock->Send(sz, sizeof(sz), 0);}}else{std::cout << "请先登录" << std::endl;pSock->Send("请先登录", sizeof("请先登录"), 0);}}}
}int main(int argc, char *argv[])
{MySocket sock;if (!sock.Create(8233, SOCK_STREAM, "127.0.0.1")){return -1;}// 获取本机信息char sSevIp[20];UINT nSevPort;sock.GetSockName(sSevIp, nSevPort);std::cout << "服务端: " << sSevIp << ":" << nSevPort << " 服务器启动成功" << std::endl;sock.Listen(5);// 获取客户端信息char sIp[20];UINT nPort;MySocket ptr;while (true){sock.Accept(ptr, sIp, &nPort);std::cout << "客户: " << sIp << ":" << nPort << " [已登录]" << std::endl;// 多线程_beginthread(ClientPro, 0, &ptr);}return 0;
}

以下是对该代码的概括:

功能:

通过 MySocket 类实现基于 TCP 协议的多线程服务器,可以处理多个客户端的连接。

实现了用户登录验证功能,支持用户登录、登出和查看本机文件列表的操作。

主要结构和功能:

登录状态记录结构体 (loginPool):记录用户登录状态,包括用户名和套接字 ID。

用户登录验证相关函数:

is_login:检查指定套接字 ID 是否已登录。

login:验证用户名和密码,如果验证通过则将用户信息加入登录池。

logout:根据套接字 ID 从登录池中移除用户。

子线程主要处理函数 ClientPro:

初始化后发送欢迎消息给客户端。

接收客户端命令,处理用户登录、登出和查看本机文件列表的请求。

针对不同的命令进行相应的处理和回复。

主线程 main:

创建服务器套接字,并通过 Create 函数创建服务器套接字。

获取本机信息,包括 IP 地址和端口,并显示在控制台。

通过 Listen 函数监听客户端连接。

接受客户端连接,创建子线程处理每个客户端连接。

通信协议:服务器与客户端之间通过简单的文本协议进行通信,支持用户登录、登出和查看本机文件列表的操作。

多线程处理:通过 _beginthread 创建子线程处理每个客户端的连接,实现了多客户端并发处理。

用户登录验证:支持用户登录验证功能,通过用户名和密码验证用户身份,记录登录状态,处理用户登录、登出的请求。

3.2 客户端流程

如下代码是一个基于 Windows 的客户端程序,通过 MySocket 类实现与服务器的基于 TCP 协议的通信。

#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include "MySocket.hpp"using namespace std;int main(int argc, char* argv[])
{MySocket sock;if (!sock.Create(0, SOCK_STREAM)){return -1;}// 获取本机信息char sClientIp[20];UINT nClientPort;sock.GetSockName(sClientIp, nClientPort);if (!sock.Connection("127.0.0.1", 8233)){cout << "连接服务器失败" << GetLastError() << endl;return -1;}char szBuffer[4096] = { 0 };int ref = sock.Receive(szBuffer, sizeof(szBuffer));szBuffer[ref] = 0;std::cout << "服务端回应: " << szBuffer << std::endl;while (true){input:memset(szBuffer, 0, 4096);std::cout << "CMD > ";// 发送命令int inputLine = 0;while ((szBuffer[inputLine++] = getchar()) != '\n');if (strlen(szBuffer) == 1)goto input;// 执行登录if (strcmp(szBuffer, "login\n") == 0){// 发送命令sock.Send(szBuffer, 4096, 0);char input_username[32] = { 0 };char input_password[32] = { 0 };// 发送用户名printf("用户名: ");scanf("%s", &input_username);sock.Send(input_username, 32, 0);// 发送密码printf("密码: ");scanf("%s", &input_password);sock.Send(input_password, 32, 0);// 获取登录状态char recv_message[64] = { 0 };sock.Receive(recv_message, 64, 0);std::cout << recv_message << std::endl;}// 登出用户else if (strcmp(szBuffer, "logout\n") == 0){// 发送命令sock.Send(szBuffer, 4096, 0);// 获取返回消息char recv_message[64] = { 0 };sock.Receive(recv_message, 64, 0);std::cout << recv_message << std::endl;}// 遍历本机文件else if (strcmp(szBuffer, "list\n") == 0){// 发送命令sock.Send(szBuffer, 4096, 0);// 获取返回消息char recv_message[64] = { 0 };sock.Receive(recv_message, 64, 0);std::cout << recv_message << std::endl;if (strcmp(recv_message, "请先登录") == 0){goto input;}// 循环接收数据包for (int x = 0; x < 10; x++){char sz[1024] = { 0 };sock.Receive(sz, 1024, 0);std::cout << sz << std::endl;}}}sock.Close();return 0;
}

以下是对该代码的概括:

功能:

通过 MySocket 类实现基于 TCP 协议的客户端,可以与服务器进行通信。

支持用户通过命令行输入与服务器进行简单的交互,包括登录、登出和查看本机文件列表的操作。

主要结构和功能:

用户交互循环:

使用一个循环,通过命令行输入命令,将命令发送给服务器,并根据服务器的回应进行相应的操作。

支持登录、登出和查看本机文件列表的操作。

命令处理:

对用户输入的不同命令,通过 sock.Send 将命令发送给服务器,并通过 sock.Receive 接收服务器的回应。

具体命令包括登录、登出和查看本机文件列表。

登录交互:

当用户输入 “login” 命令时,程序会提示用户输入用户名和密码,并将输入的用户名和密码发送给服务器进行登录验证。

接收服务器的回应,输出相应的登录状态信息。

登出交互:

当用户输入 “logout” 命令时,程序向服务器发送登出命令,接收服务器的回应并输出相应的信息。

查看本机文件列表交互:

当用户输入 “list” 命令时,程序向服务器发送查看本机文件列表的命令,接收服务器的回应并输出相应的信息。

如果用户未登录,则输出 “请先登录” 提示,并继续等待用户输入。

通信协议:客户端与服务器之间通过简单的文本协议进行通信,服务器回应的信息通过控制台输出。

与之前的程序不同,这段代码增加了简单的用户认证模式,当用户直接执行命令时则会提示客户端请先登录,无法执行命令;

此时通过login命令,并输入用户名lyshark密码123123则会提示已登录,此时就可以执行任意的命令参数了,如下图所示,当结束时还需要使用logout退出当前会话;

 粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

点云数据处理常用外部库(C++/Windows)的项目配置

一、点云数据处理常用外部库&#xff08;C版本&#xff09;的下载安装与项目配置 &#xff08;一&#xff09;PCL 基于VS2019编程平台的PCL外部库下载安装及项目配置已有大量博客&#xff0c;本文不再赘述。具体下载安装及项目配置流程可参考外部库编译配置参考资料/*1*/ 。需…

OPENSSL-PKCS7入门知识介绍

1 PKCS7数据结构说明 p7包括6种数据内容&#xff1a;数据(data),签名数据&#xff08;sign&#xff09;&#xff0c;数字信封数据&#xff08;enveloped&#xff09;&#xff0c;签名数字信封数据&#xff08;signed_and_enveloped&#xff09;&#xff0c;摘要数据&#xff08…

ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘无密码如何解决

1.修改my.cnf配置文件 &#xff08;1&#xff09;找到my.cnf位置&#xff0c;在[mysqld]下面添加skip-grant-tables cd / vim /etc/my.cnf &#xff08;2&#xff09;添加完成后保存&#xff0c;并重启mysql服务 按下esc 输入:wq 执行 servcie mysqld restart 2.进入mysql数据…

300分钟吃透分布式缓存-14讲:大数据时代,MC如何应对新的常见问题?

大数据时代 Memcached 经典问题 随着互联网的快速发展和普及&#xff0c;人类进入了大数据时代。在大数据时代&#xff0c;移动设备全面融入了人们的工作和生活&#xff0c;各种数据以前所未有的 速度被生产、挖掘和消费。移动互联网系统也不断演进和发展&#xff0c;存储、计…

Matlab论文插图绘制模板第138期—极坐标直方图

在之前的文章中&#xff0c;分享了Matlab一系列极坐标下的插图绘制模板&#xff1a; 本期再来分享一下极坐标直方图的绘制模板。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下载。有需要的朋友可以…

MySQL多实例与Mycat分布式读写分离的架构实践

文章目录 1.Mycat读写分离分布式架构规划2.在两台服务器中搭建八个MySQL实例2.1.安装MySQL软件2.2.创建每个MySQL实例的数据目录并初始化2.3.准备每个实例的配置文件2.4.准备每个实例的启动脚本2.6启动每台机器的MySQL多实例2.7.为每个MySQL实例设置密码2.8.查看每个MySQL实例的…

项目启动∣新一代亿元级国民零食品牌「比比赞」携手企企通,合力打造企业级数字化采购与供应链管理平台

为进一步提升企业的核心供应链一体化协同管理&#xff0c;助力企业效益提升&#xff0c;近日&#xff0c;泉州市丰泽区尚客食品有限公司&#xff08;以下简称“比比赞”&#xff09;与企企通携手&#xff0c;成功召开SRM项目启动会。 会议期间&#xff0c;双方对项目背景、项目…

Oracle内存计算应用模式

前言 内存计算是利用内存来加速数据访问和应用的性能&#xff0c;并降低应用开发复杂度的技术。近十年来&#xff0c;随着软硬件技术的发展和用户需求的成熟&#xff0c;内存计算技术已经得到了广泛地应用。 Oracle在内存计算领域具有非常重要的地位&#xff0c;这主要得益于…

开了抖店该怎么玩?不知道运营流程的,今天一文带你了解!

大家好&#xff0c;我是电商小布。 在电商的快速发展下&#xff0c;越来越多的新手小伙伴开始加入其中。 抖音小店作为当前的低成本创业项目&#xff0c;吸引到了很多的新手朋友加入其中。 但是开店后怎么玩&#xff0c;如何做好运营操作呢&#xff1f; 今天&#xff0c;小…

WampServer环境下载安装并结合内网穿透实现远程访问管理界面

文章目录 前言1.WampServer下载安装2.WampServer启动3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4.固定公网地址访问 前言 Wamp 是一个 Windows系统下的 Apache PHP Mysql 集成安装环境&#xff0c;是一组常用来…

AI论文速读 | 【综述】(LLM4TS)大语言模型用于时间序列

题目&#xff1a;Large Language Models for Time Series: A Survey 作者&#xff1a;Xiyuan Zhang , Ranak Roy Chowdhury , Rajesh K. Gupta and Jingbo Shang 机构&#xff1a;加州大学圣地亚哥分校&#xff08;UCSD&#xff09; 网址&#xff1a;https://arxiv.org/abs/…

CleanMyMac2024一款备受赞誉的mac电脑垃圾清理软件

在数字世界中&#xff0c;我们的Mac不仅仅是一台电脑&#xff0c;更是我们工作、娱乐和生活的得力助手。然而&#xff0c;随着时间的推移&#xff0c;系统垃圾、无用文件和缓存不断堆积&#xff0c;让Mac变得迟钝&#xff0c;甚至威胁到我们的数据安全。此刻&#xff0c;您需要…

《Docker 简易速速上手小册》第6章 Docker 网络与安全(2024 最新版)

文章目录 6.1 Docker 网络概念6.1.1 重点基础知识6.1.2 重点案例&#xff1a;基于 Flask 的微服务6.1.3 拓展案例 1&#xff1a;容器间的直接通信6.1.4 拓展案例 2&#xff1a;跨主机容器通信 6.2 配置与管理网络6.2.1 重点基础知识6.2.2 重点案例&#xff1a;配置 Flask 应用的…

vite搭配vue2创建工程

一、安装vite npm init vite2.8.0 vite默认支持的是vue3&#xff0c; 这里选择框架和版本vanilla&#xff0c; 方便以后自己安装vue2. 二、修改package.json 默认生成的pacakage.json文件 {"name": "vite-project","private": true,"v…

开源项目---集成系信息管理平台

文章目录 概要整体架构流程内置的功能介绍系统演示小结 概要 提示&#xff1a;开源信息管理平台 主要是进行的是对于大部分的管理信息平台的综合&#xff0c;以及进行相关的开源项目的改造和升级&#xff0c;添加新的功能的同时&#xff0c;也是为了更好的让大家一起学习&#…

优优嗨聚集团:法律咨询服务,守护您生活的每一份权益

在当今社会&#xff0c;随着法治意识的日益增强&#xff0c;法律咨询服务的重要性愈发凸显。无论是个人还是企业&#xff0c;面对纷繁复杂的法律环境&#xff0c;专业的法律咨询服务成为了不可或缺的护航者。 一、法律咨询服务&#xff1a;个人权益的守护者 在日常生活中&…

手机和windows的便签怎么共享账号使用

在忙碌的生活中&#xff0c;我经常需要在手机和电脑之间同步记事信息。可是&#xff0c;每次当我在手机上记下一些重要事项后&#xff0c;想要在电脑上查看或继续编辑时&#xff0c;总是遇到各种麻烦。因为手机和电脑上的便签软件各不相同&#xff0c;无法实现账号共享和内容同…

Object中的hashCode()

让hashcode方法的返回值为地址 vm参数中输入-XX:UnlockExperimentalVMOptions -XX:hashCode4&#xff0c;如下图&#xff1a; 参考 搞懂JAVAObject中的hashCode()_java_脚本之家 JDK核心JAVA源码解析(9) - hashcode 方法 - 知乎

护眼台灯怎么选?五大2024年口碑台灯力荐!

护眼台灯算得上是近年来家长为孩子置办最多的用品之一&#xff0c;作为一名十分关注各类市场的测评师&#xff0c;我时刻关注各种家电、灯具的走向&#xff0c;也结合实际的使用&#xff0c;为广大用户提供专业深度的护眼台灯测评。对于护眼台灯&#xff0c;消费者的评价褒贬不…

git之远程操作

一.分布式版本控制系统 分布式版本控制系统通常也有⼀台充当“中央服务器”的电脑&#xff0c;但这个服务器的作⽤仅仅是⽤来⽅便“交换”⼤家的修改&#xff0c;没有它⼤家也⼀样⼲活&#xff0c;只是交换修改不⽅便⽽已。有了这个“中央服务器”的电脑&#xff0c;这样就不怕…