Windows下用MinGW和VSCode手把手搭建C++ WebSocket通信(附完整代码和避坑指南)

news2026/4/29 15:57:41
Windows平台C WebSocket开发实战从环境搭建到双端通信在Windows环境下使用C进行WebSocket开发既能满足高性能需求又能充分利用Windows平台的特性。本文将带你从零开始完成MinGW和VSCode的环境配置实现完整的WebSocket通信功能并解决开发过程中可能遇到的各种问题。1. 开发环境配置与工具链搭建1.1 MinGW安装与系统路径配置MinGWMinimalist GNU for Windows是Windows平台上的GNU工具链移植版本我们需要它来提供g编译器等开发工具。安装步骤访问MinGW官网下载安装管理器运行安装程序选择安装位置建议使用不含空格的路径在基础包中选择以下组件mingw32-basemingw32-gcc-gmsys-base安装完成后需要将MinGW的bin目录添加到系统PATH环境变量中# 假设MinGW安装在C:\mingw64 setx PATH %PATH%;C:\mingw64\bin验证安装是否成功g --version如果看到类似g (MinGW.org GCC Build-2) 9.2.0的输出说明安装成功。1.2 VSCode开发环境配置Visual Studio Code是轻量级但功能强大的代码编辑器特别适合C开发。必要扩展安装C/C (Microsoft官方扩展)CMake Tools (如果需要构建复杂项目)Code Runner (快速运行代码)配置C开发环境需要创建.vscode文件夹并添加以下文件c_cpp_properties.json(编译器路径配置){ configurations: [ { name: Win32, includePath: [ ${workspaceFolder}/**, C:/mingw64/include/** ], defines: [], compilerPath: C:/mingw64/bin/g.exe, cStandard: c11, cppStandard: c17, intelliSenseMode: gcc-x64 } ], version: 4 }tasks.json(构建任务配置){ version: 2.0.0, tasks: [ { label: build websocket, type: shell, command: g, args: [ -g, ${file}, -o, ${fileDirname}\\${fileBasenameNoExtension}.exe, -lws2_32 ], group: { kind: build, isDefault: true } } ] }2. WebSocket基础与Windows Socket API2.1 WebSocket协议概述WebSocket是一种在单个TCP连接上进行全双工通信的协议与HTTP的主要区别在于特性HTTPWebSocket连接方式短连接长连接通信方向单向双向数据格式文本/二进制文本/二进制头部开销较大较小适用场景请求-响应实时通信2.2 Windows Socket编程基础Windows平台下的Socket编程需要先初始化Winsock库这是所有网络操作的前提#include winsock2.h #include ws2tcpip.h #pragma comment(lib, ws2_32.lib) // 初始化Winsock WSADATA wsaData; int result WSAStartup(MAKEWORD(2, 2), wsaData); if (result ! 0) { printf(WSAStartup failed: %d\n, result); return 1; }关键API函数及其作用socket(): 创建通信端点bind(): 将socket与本地地址绑定listen(): 开始监听连接请求accept(): 接受连接请求connect(): 发起连接请求send()/recv(): 发送和接收数据closesocket(): 关闭socketWSACleanup(): 清理Winsock资源3. WebSocket服务端实现3.1 服务端核心代码结构完整的WebSocket服务端需要处理以下流程创建监听socket绑定到指定端口开始监听接受客户端连接处理WebSocket握手实现消息收发循环基础TCP服务端实现SOCKET serverSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverSocket INVALID_SOCKET) { printf(socket creation failed: %d\n, WSAGetLastError()); WSACleanup(); return 1; } sockaddr_in serverAddr; serverAddr.sin_family AF_INET; serverAddr.sin_addr.s_addr INADDR_ANY; serverAddr.sin_port htons(8080); if (bind(serverSocket, (SOCKADDR*)serverAddr, sizeof(serverAddr)) SOCKET_ERROR) { printf(bind failed: %d\n, WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return 1; } if (listen(serverSocket, SOMAXCONN) SOCKET_ERROR) { printf(listen failed: %d\n, WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return 1; } printf(Server is listening on port 8080...\n);3.2 WebSocket握手协议实现WebSocket连接始于HTTP升级请求服务端需要正确响应才能建立WebSocket连接std::string readClientRequest(SOCKET clientSocket) { char buffer[1024]; int bytesRead recv(clientSocket, buffer, sizeof(buffer), 0); if (bytesRead 0) { return std::string(buffer, bytesRead); } return ; } bool handleHandshake(SOCKET clientSocket, const std::string request) { // 解析Sec-WebSocket-Key std::string key; size_t keyStart request.find(Sec-WebSocket-Key:); if (keyStart ! std::string::npos) { keyStart request.find_first_not_of( \t, keyStart 18); size_t keyEnd request.find(\r\n, keyStart); key request.substr(keyStart, keyEnd - keyStart); } if (key.empty()) { return false; } // 计算响应key std::string magicString 258EAFA5-E914-47DA-95CA-C5AB0DC85B11; std::string combined key magicString; unsigned char sha1Hash[20]; SHA1(reinterpret_castconst unsigned char*(combined.c_str()), combined.length(), sha1Hash); std::string acceptKey base64_encode(sha1Hash, 20); // 发送握手响应 std::string response HTTP/1.1 101 Switching Protocols\r\n Upgrade: websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Accept: acceptKey \r\n\r\n; send(clientSocket, response.c_str(), response.length(), 0); return true; }4. WebSocket客户端实现4.1 客户端核心代码结构WebSocket客户端需要创建socket连接到服务端发送WebSocket握手请求处理服务端响应实现消息收发循环基础TCP客户端实现SOCKET clientSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientSocket INVALID_SOCKET) { printf(socket creation failed: %d\n, WSAGetLastError()); WSACleanup(); return 1; } sockaddr_in serverAddr; serverAddr.sin_family AF_INET; serverAddr.sin_addr.s_addr inet_addr(127.0.0.1); serverAddr.sin_port htons(8080); if (connect(clientSocket, (SOCKADDR*)serverAddr, sizeof(serverAddr)) SOCKET_ERROR) { printf(connect failed: %d\n, WSAGetLastError()); closesocket(clientSocket); WSACleanup(); return 1; } printf(Connected to server\n);4.2 WebSocket握手请求构造客户端需要构造符合标准的WebSocket握手请求std::string generateHandshakeRequest(const std::string host, const std::string path) { std::string key; const char chars[] ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/; // 生成随机key for (int i 0; i 16; i) { key chars[rand() % 64]; } key base64_encode(reinterpret_castconst unsigned char*(key.c_str()), 16); std::string request GET path HTTP/1.1\r\n Host: host \r\n Upgrade: websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Key: key \r\n Sec-WebSocket-Version: 13\r\n Origin: http:// host \r\n\r\n; return request; }5. 消息编解码与通信实现5.1 WebSocket数据帧格式WebSocket协议定义了特定的数据帧格式理解这个格式对于实现通信至关重要0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------------------------------- |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len126/127) | | |1|2|3| |K| | | ------------------------- - - - - - - - - - - - - - - - | Extended payload length continued, if payload len 127 | - - - - - - - - - - - - - - - ------------------------------- | |Masking-key, if MASK set to 1 | -------------------------------------------------------------- | Masking-key (continued) | Payload Data | -------------------------------- - - - - - - - - - - - - - - - : Payload Data continued ... : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | Payload Data continued ... | ---------------------------------------------------------------5.2 消息编码实现发送消息时需要按照WebSocket帧格式编码数据std::vectorunsigned char encodeWebSocketFrame(const std::string message, int opcode 0x1) { std::vectorunsigned char frame; // FIN opcode frame.push_back(0x80 | (opcode 0x0F)); // Mask payload length size_t length message.size(); if (length 125) { frame.push_back(static_castunsigned char(length)); } else if (length 65535) { frame.push_back(126); frame.push_back(static_castunsigned char((length 8) 0xFF)); frame.push_back(static_castunsigned char(length 0xFF)); } else { frame.push_back(127); for (int i 7; i 0; --i) { frame.push_back(static_castunsigned char((length (8 * i)) 0xFF)); } } // Payload frame.insert(frame.end(), message.begin(), message.end()); return frame; }5.3 消息解码实现接收消息时需要解析WebSocket帧std::string decodeWebSocketFrame(const std::vectorunsigned char data) { if (data.size() 2) return ; size_t index 0; unsigned char firstByte data[index]; unsigned char secondByte data[index]; bool fin (firstByte 0x80) ! 0; int opcode firstByte 0x0F; bool masked (secondByte 0x80) ! 0; size_t payloadLength secondByte 0x7F; if (payloadLength 126) { if (data.size() index 2) return ; payloadLength (data[index] 8) | data[index 1]; index 2; } else if (payloadLength 127) { if (data.size() index 8) return ; payloadLength 0; for (int i 0; i 8; i) { payloadLength (payloadLength 8) | data[index]; } } std::vectorunsigned char maskingKey; if (masked) { if (data.size() index 4) return ; maskingKey.assign(data.begin() index, data.begin() index 4); index 4; } if (data.size() index payloadLength) return ; std::string payload; for (size_t i 0; i payloadLength; i) { unsigned char byte data[index i]; if (masked) { byte ^ maskingKey[i % 4]; } payload.push_back(static_castchar(byte)); } return payload; }6. 常见问题与调试技巧6.1 编译与链接问题问题1undefined reference to WSAStartup等链接错误解决方案确保在编译命令中添加了-lws2_32选项g websocket_server.cpp -o server -lws2_32问题2中文乱码问题解决方案在代码开头添加执行字符集设置#pragma execution_character_set(utf-8)或者在编译时指定编码g -fexec-charsetUTF-8 source.cpp -o output6.2 运行时问题问题1bind failed: 10048 (Address already in use)解决方案该端口已被占用可以等待一段时间让系统释放端口选择其他端口设置SO_REUSEADDR选项int opt 1; setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)opt, sizeof(opt));问题2连接不稳定或意外断开解决方案实现心跳机制保持连接活跃增加错误处理和重连逻辑检查防火墙设置是否阻止了连接6.3 WebSocket特定问题问题1握手失败返回400 Bad Request解决方案检查握手请求格式是否正确确保Sec-WebSocket-Key生成正确验证HTTP头结束符是\r\n\r\n问题2接收到的消息乱码或格式错误解决方案确保正确实现了WebSocket帧解析检查是否正确处理了掩码验证发送方是否按照协议格式发送数据7. 性能优化与高级特性7.1 多客户端处理基础实现只能处理单个客户端实际应用中需要支持多客户端连接// 创建主socket SOCKET serverSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 设置非阻塞模式 u_long mode 1; ioctlsocket(serverSocket, FIONBIO, mode); // 创建fd_set结构 fd_set masterSet; FD_ZERO(masterSet); FD_SET(serverSocket, masterSet); while (true) { fd_set readSet masterSet; int socketCount select(0, readSet, nullptr, nullptr, nullptr); for (int i 0; i socketCount; i) { SOCKET sock readSet.fd_array[i]; if (sock serverSocket) { // 新连接 SOCKET client accept(serverSocket, nullptr, nullptr); FD_SET(client, masterSet); } else { // 已有连接的数据 char buffer[4096]; int bytesReceived recv(sock, buffer, sizeof(buffer), 0); if (bytesReceived 0) { closesocket(sock); FD_CLR(sock, masterSet); } else { // 处理接收到的数据 // ... } } } }7.2 SSL/TLS支持安全通信需要添加SSL/TLS支持可以使用OpenSSL库#include openssl/ssl.h #include openssl/err.h // 初始化OpenSSL SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); // 创建SSL上下文 SSL_CTX* ctx SSL_CTX_new(TLS_server_method()); if (!SSL_CTX_use_certificate_file(ctx, server.crt, SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(ctx, server.key, SSL_FILETYPE_PEM)) { ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } // 为socket创建SSL对象 SSL* ssl SSL_new(ctx); SSL_set_fd(ssl, clientSocket); // SSL握手 if (SSL_accept(ssl) 0) { ERR_print_errors_fp(stderr); } else { // 使用SSL_read/SSL_write代替recv/send char buffer[1024]; int bytes SSL_read(ssl, buffer, sizeof(buffer)); // ... } // 清理 SSL_free(ssl); SSL_CTX_free(ctx);7.3 性能优化技巧缓冲区管理预分配缓冲区避免频繁内存分配批量处理合并小消息为批量发送零拷贝使用sendfile等系统调用减少数据拷贝I/O多路复用使用select/poll/epoll等提高并发能力协议优化设计紧凑的二进制协议减少传输开销8. 完整示例与测试8.1 服务端完整代码#include winsock2.h #include ws2tcpip.h #include stdio.h #include string #include vector #include openssl/sha.h #include openssl/evp.h #include wincrypt.h #pragma comment(lib, ws2_32.lib) #pragma comment(lib, crypt32.lib) std::string base64_encode(const unsigned char* input, size_t length) { DWORD outputLength; CryptBinaryToStringA(input, static_castDWORD(length), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, outputLength); std::string output(outputLength, \0); CryptBinaryToStringA(input, static_castDWORD(length), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, output[0], outputLength); return output; } std::string readClientRequest(SOCKET clientSocket) { char buffer[1024]; int bytesRead recv(clientSocket, buffer, sizeof(buffer), 0); if (bytesRead 0) { return std::string(buffer, bytesRead); } return ; } bool handleHandshake(SOCKET clientSocket, const std::string request) { size_t keyStart request.find(Sec-WebSocket-Key:); if (keyStart std::string::npos) return false; keyStart request.find_first_not_of( \t, keyStart 18); size_t keyEnd request.find(\r\n, keyStart); std::string key request.substr(keyStart, keyEnd - keyStart); std::string magic 258EAFA5-E914-47DA-95CA-C5AB0DC85B11; std::string combined key magic; unsigned char sha1Hash[20]; SHA1(reinterpret_castconst unsigned char*(combined.c_str()), combined.length(), sha1Hash); std::string acceptKey base64_encode(sha1Hash, 20); std::string response HTTP/1.1 101 Switching Protocols\r\n Upgrade: websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Accept: acceptKey \r\n\r\n; send(clientSocket, response.c_str(), response.length(), 0); return true; } std::string decodeWebSocketFrame(const std::vectorunsigned char data) { if (data.size() 2) return ; size_t index 0; bool fin (data[index] 0x80) ! 0; int opcode data[index] 0x0F; bool masked (data[index] 0x80) ! 0; size_t payloadLength data[index] 0x7F; if (payloadLength 126) { if (data.size() index 2) return ; payloadLength (data[index] 8) | data[index 1]; index 2; } else if (payloadLength 127) { if (data.size() index 8) return ; payloadLength 0; for (int i 0; i 8; i) { payloadLength (payloadLength 8) | data[index]; } } std::vectorunsigned char maskingKey; if (masked) { if (data.size() index 4) return ; maskingKey.assign(data.begin() index, data.begin() index 4); index 4; } if (data.size() index payloadLength) return ; std::string payload; for (size_t i 0; i payloadLength; i) { unsigned char byte data[index i]; if (masked) { byte ^ maskingKey[i % 4]; } payload.push_back(static_castchar(byte)); } return payload; } std::vectorunsigned char encodeWebSocketFrame(const std::string message) { std::vectorunsigned char frame; frame.push_back(0x81); // FIN text frame size_t length message.size(); if (length 125) { frame.push_back(static_castunsigned char(length)); } else if (length 65535) { frame.push_back(126); frame.push_back(static_castunsigned char((length 8) 0xFF)); frame.push_back(static_castunsigned char(length 0xFF)); } else { frame.push_back(127); for (int i 7; i 0; --i) { frame.push_back(static_castunsigned char((length (8 * i)) 0xFF)); } } frame.insert(frame.end(), message.begin(), message.end()); return frame; } int main() { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) { printf(WSAStartup failed\n); return 1; } SOCKET serverSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverSocket INVALID_SOCKET) { printf(socket failed: %d\n, WSAGetLastError()); WSACleanup(); return 1; } sockaddr_in serverAddr; serverAddr.sin_family AF_INET; serverAddr.sin_addr.s_addr INADDR_ANY; serverAddr.sin_port htons(8080); if (bind(serverSocket, (SOCKADDR*)serverAddr, sizeof(serverAddr)) SOCKET_ERROR) { printf(bind failed: %d\n, WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return 1; } if (listen(serverSocket, SOMAXCONN) SOCKET_ERROR) { printf(listen failed: %d\n, WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return 1; } printf(Server listening on port 8080...\n); SOCKET clientSocket accept(serverSocket, nullptr, nullptr); if (clientSocket INVALID_SOCKET) { printf(accept failed: %d\n, WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return 1; } std::string request readClientRequest(clientSocket); if (!handleHandshake(clientSocket, request)) { printf(handshake failed\n); closesocket(clientSocket); closesocket(serverSocket); WSACleanup(); return 1; } printf(WebSocket connection established\n); while (true) { char buffer[1024]; int bytesRead recv(clientSocket, buffer, sizeof(buffer), 0); if (bytesRead 0) break; std::vectorunsigned char data(buffer, buffer bytesRead); std::string message decodeWebSocketFrame(data); printf(Received: %s\n, message.c_str()); std::string response Echo: message; std::vectorunsigned char frame encodeWebSocketFrame(response); send(clientSocket, reinterpret_castconst char*(frame.data()), frame.size(), 0); } closesocket(clientSocket); closesocket(serverSocket); WSACleanup(); return 0; }8.2 客户端完整代码#include winsock2.h #include ws2tcpip.h #include stdio.h #include string #include vector #include openssl/sha.h #include openssl/evp.h #include wincrypt.h #pragma comment(lib, ws2_32.lib) #pragma comment(lib, crypt32.lib) std::string base64_encode(const unsigned char* input, size_t length) { DWORD outputLength; CryptBinaryToStringA(input, static_castDWORD(length), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, outputLength); std::string output(outputLength, \0); CryptBinaryToStringA(input, static_castDWORD(length), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, output[0], outputLength); return output; } std::string generateHandshakeRequest() { const char chars[] ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/; std::string key; for (int i 0; i 16; i) { key chars[rand() % 64]; } return base64_encode(reinterpret_castconst unsigned char*(key.c_str()), 16); } std::vectorunsigned char encodeWebSocketFrame(const std::string message) { std::vectorunsigned char frame; frame.push_back(0x81); // FIN text frame size_t length message.size(); if (length 125) { frame.push_back(static_castunsigned char(length)); } else if (length 65535) { frame.push_back(126); frame.push_back(static_castunsigned char((length 8) 0xFF)); frame.push_back(static_castunsigned char(length 0xFF)); } else { frame.push_back(127); for (int i 7; i 0; --i) { frame.push_back(static_castunsigned char((length (8 * i)) 0xFF)); } } frame.insert(frame.end(), message.begin(), message.end()); return frame; } std::string decodeWebSocketFrame(const std::vectorunsigned char data) { if (data.size() 2) return ; size_t index 0; bool fin (data[index] 0x80) ! 0; int opcode data[index] 0x0F; bool masked (data[index] 0x80) ! 0; size_t payloadLength data[index] 0x7F; if (payloadLength 126) { if (data.size() index 2) return ; payloadLength (data[index] 8) | data[index 1]; index 2; } else if (payloadLength 127) { if (data.size() index 8) return ; payloadLength 0; for (int i 0; i 8; i) { payloadLength (payloadLength 8) | data[index]; } } std::vectorunsigned char maskingKey; if (masked) { if (data.size() index 4) return ; maskingKey.assign(data.begin() index, data.begin() index 4); index 4; } if (data.size() index payloadLength) return ; std::string payload; for (size_t i 0; i payloadLength; i) { unsigned char byte data[index i]; if (masked) { byte ^ maskingKey[i % 4]; } payload.push_back(static_castchar(byte)); } return payload; } int main() { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), wsaData) ! 0) { printf(WSAStartup failed\n); return 1; } SOCKET clientSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientSocket INVALID_SOCKET) { printf(socket failed: %d\n, WSAGetLastError()); WSACleanup(); return 1; } sockaddr_in serverAddr; serverAddr.sin_family AF_INET; serverAddr.sin_addr.s_addr inet_addr(127.0.0.1); serverAddr.sin_port htons(8080); if (connect(clientSocket, (SOCKADDR*)serverAddr, sizeof(serverAddr)) SOCKET_ERROR) { printf(connect failed: %d\n, WSAGetLastError()); closesocket(clientSocket); WSACleanup(); return 1; } std::string key generateHandshakeRequest(); std::string request GET / HTTP/1.1\r\n Host: localhost:8080\r\n Upgrade: websocket\r\n Connection: Upgrade\r\n Sec-WebSocket-Key: key \r\n Sec-WebSocket-Version: 13\r\n\r\n; send(clientSocket, request.c_str(), request.length(), 0); char buffer[1024]; int bytesRead recv(clientSocket, buffer, sizeof(buffer), 0); if (bytesRead 0) { printf(handshake failed\n); closesocket(clientSocket); WSACleanup(); return 1; } printf(WebSocket connection established\n); while (true) { printf(Enter message (or quit to exit): ); char input[256]; fgets(input, sizeof(input), stdin); input[strcspn(input, \n)] \0; std::string message(input); if (message quit) break; std::vectorunsigned char frame encodeWebSocketFrame(message); send(clientSocket, reinterpret_castconst char*(frame.data()), frame.size(), 0); bytesRead recv(clientSocket, buffer, sizeof(buffer), 0); if (bytesRead 0) break; std::vectorunsigned char data(buffer, buffer bytesRead); std::string response decodeWebSocketFrame(data); printf(Server response: %s\n, response.c_str()); } closesocket(clientSocket); WSACleanup(); return 0; }8.3 编译与测试步骤编译服务端g websocket_server.cpp -o server -lws2_32 -lcrypt32编译客户端g websocket_client.cpp -o client -lws2_32 -lcrypt32运行服务端./server运行客户端./client测试通信在客户端输入消息并回车发送服务端会回显收到的消息输入quit退出客户端9. 进阶方向与资源推荐9.1 进一步学习方向协议扩展实现WebSocket子协议和扩展性能优化研究I/O多路复用和异步编程模型安全增强添加身份验证和授权机制集群部署实现负载均衡和高可用架构跨平台开发移植到Linux/macOS等其他平台9.2 推荐资源书籍《TCP/IP详解 卷1协议》《Unix网络编程》《WebSocket权威指南》在线资源RFC 645

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…