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

学懂C++(三十八):深入详解C++网络编程:套接字(Socket)开发技术

目录

一、概述与基础概念

1.1 套接字(Socket)概念

1.2 底层原理与网络协议

1.2.1 网络协议

1.2.2 套接字工作原理

二、C++套接字编程核心技术

2.1 套接字编程的基本步骤

2.2 套接字编程详细实现

2.2.1 创建套接字

2.2.2 绑定地址

2.2.3 监听和接受连接(服务端)

2.2.4 客户端连接

2.2.5 发送和接收数据

2.2.6 关闭套接字

2.3 经典实例:TCP客户端和服务器

2.3.1 TCP服务器

2.3.2 TCP客户端

运行结果

三、深入理解与高级应用

3.1 异步I/O与事件驱动编程

3.2 高效并发编程

3.3 使用Boost.Asio进行异步编程

完整代码示例:使用Boost.Asio进行异步TCP服务器

BoostServer.cpp

四、核心技术及高级话题

4.1 同步I/O与异步I/O的选择

4.2 多线程与事件驱动模型

4.3 高效网络编程的关键技术

4.4 使用C++11/14/17/20新特性优化网络编程

五、实例:高效异步HTTP服务器

5.1 异步HTTP服务器

运行结果

六、拓展思考

1、套接字(Socket)是什么?它包括哪些核心内容?

套接字的定义

套接字的核心内容

1. 套接字类型

2. 地址族

3. 套接字的基本操作

套接字的高级内容

2、套接字 socket是基于哪个网络协议的?是TCP还是Http?

总结


网络编程是现代软件开发的重要领域,广泛应用于客户端-服务器应用、分布式系统和互联网应用开发中。C++作为一门强大且高效的编程语言,在进行低层次、高性能网络编程时有显著优势。本文将深入剖析C++网络编程中的套接字(Socket)开发技术,详细讲解其概念、底层原理、网络协议知识、本质及需要掌握的核心点、实现方式等,同时结合经典实例进行解析。

一、概述与基础概念

1.1 套接字(Socket)概念

概念:套接字(Socket)是网络编程中用于描述网络连接的端点,是操作系统提供的用于网络通信的基础抽象。它可以看作是网络中的“文件”,通过对套接字的操作实现数据的发送和接收。

核心点

  • 类型:主要包括流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM),分别对应TCP和UDP协议。
  • 地址:由IP地址和端口号组成,用于标识网络中的设备和应用。

1.2 底层原理与网络协议

1.2.1 网络协议

IP地址:标识网络中的主机,分为IPv4(如192.168.1.1)和IPv6(如2001:db8::1)地址。

端口号:标识主机上的应用程序,范围为0到65535。常见的端口号如HTTP的80端口、HTTPS的443端口等。

TCP/IP协议族:互联网的基础协议族,包含传输层的TCP和UDP、网络层的IP等。

  • TCP(传输控制协议):提供可靠的字节流服务,包括连接建立、数据传输、连接终止等过程。TCP通过三次握手建立连接,四次挥手终止连接。
  • UDP(用户数据报协议):提供不可靠的消息传递服务,数据报可能无序到达或丢失。UDP适用于实时性要求较高的应用,如视频传输、在线游戏等。
1.2.2 套接字工作原理

套接字是一种抽象层,使得应用程序能够通过操作系统提供的API进行网络通信。它包含以下基本操作:

  • 创建:通过系统调用创建套接字。
  • 绑定:将套接字绑定到特定的IP地址和端口。
  • 监听:在服务端,套接字监听来自客户端的连接请求。
  • 连接:在客户端,套接字连接到服务端的指定地址和端口。
  • 发送/接收:通过套接字发送和接收数据。
  • 关闭:关闭套接字,释放系统资源。

二、C++套接字编程核心技术

2.1 套接字编程的基本步骤

  1. 创建套接字
  2. 绑定地址
  3. 监听(服务端)
  4. 接受连接(服务端)
  5. 连接(客户端)
  6. 发送和接收数据
  7. 关闭套接字

2.2 套接字编程详细实现

2.2.1 创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {perror("socket creation failed");exit(EXIT_FAILURE);
}

解析

  • socket(AF_INET, SOCK_STREAM, 0):创建一个TCP套接字。AF_INET表示使用IPv4,SOCK_STREAM表示使用TCP协议。
  • 返回值:成功时返回套接字文件描述符,失败时返回-1。
2.2.2 绑定地址
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind failed");close(sockfd);exit(EXIT_FAILURE);
}

解析

  • struct sockaddr_in:定义IP地址和端口,sin_family设为AF_INETsin_addr.s_addr设为INADDR_ANY表示接受任何IP地址,sin_port设为端口(通过htons函数转换为网络字节序)。
  • bind:将地址绑定到套接字。
2.2.3 监听和接受连接(服务端)
if (listen(sockfd, 5) < 0) {perror("listen failed");close(sockfd);exit(EXIT_FAILURE);
}struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int newsockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
if (newsockfd < 0) {perror("accept failed");close(sockfd);exit(EXIT_FAILURE);
}

解析

  • listen:将套接字置于监听模式,准备接受连接。第二个参数为连接队列的最大长度。
  • accept:接受客户端连接,返回新的套接字用于通信。client_addr保存客户端地址信息。
2.2.4 客户端连接
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {perror("invalid address");exit(EXIT_FAILURE);
}if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("connect failed");close(sockfd);exit(EXIT_FAILURE);
}

解析

  • inet_pton:将字符串形式的IP地址转换为struct in_addr
  • connect:将套接字连接到指定的服务器地址和端口。
2.2.5 发送和接收数据
const char* message = "Hello, Server!";
send(sockfd, message, strlen(message), 0);char buffer[1024];
int n = recv(sockfd, buffer, sizeof(buffer), 0);
buffer[n] = '\0';
printf("Received: %s\n", buffer);

解析

  • send:发送数据,第四个参数为标志位,通常为0。
  • recv:接收数据,返回接收的字节数。
2.2.6 关闭套接字
close(sockfd);

2.3 经典实例:TCP客户端和服务器

2.3.1 TCP服务器
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>#define PORT 8080int main() {int server_fd, new_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};const char* hello = "Hello from server";// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 强制绑定端口if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt");close(server_fd);exit(EXIT_FAILURE);}// 绑定地址address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {perror("bind failed");close(server_fd);exit(EXIT_FAILURE);}// 监听连接if (listen(server_fd, 3) < 0) {perror("listen");close(server_fd);exit(EXIT_FAILURE);}// 接受客户端连接if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");close(server_fd);exit(EXIT_FAILURE);}// 读取客户端数据int valread = read(new_socket, buffer, 1024);printf("%s\n", buffer);// 发送数据到客户端send(new_socket, hello, strlen(hello), 0);printf("Hello message sent\n");// 关闭套接字close(new_socket);close(server_fd);return 0;
}

解析

  • 创建套接字socket(AF_INET, SOCK_STREAM, 0)
  • 绑定地址bind
  • 监听连接listen
  • 接受连接accept
  • 读取数据read
  • 发送数据send
  • 关闭套接字close
2.3.2 TCP客户端
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 8080int main() {int sock = 0, valread;struct sockaddr_in serv_addr;const char* hello = "Hello from client";char buffer[1024] = {0};// 创建套接字if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("Socket creation error");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// 将IP地址转换成二进制形式if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {perror("Invalid address/ Address not supported");return -1;}// 连接服务器if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection Failed");return -1;}// 发送数据到服务器send(sock, hello, strlen(hello), 0);printf("Hello message sent\n");// 读取服务器响应valread = read(sock, buffer, 1024);printf("%s\n", buffer);// 关闭套接字close(sock);return 0;
}

解析

  • 创建套接字socket(AF_INET, SOCK_STREAM, 0)
  • 连接服务器connect
  • 发送数据send
  • 读取数据read
  • 关闭套接字close

运行结果

  1. 启动服务器:

    ./server
    

    输出

    Hello from client
    Hello message sent
    
  2. 启动客户端:

    ./client
    

    输出

    Hello message sent
    Hello from server
    

三、深入理解与高级应用

3.1 异步I/O与事件驱动编程

异步I/O:允许程序在等待I/O操作完成时继续执行其他任务,提高程序的并发性能。实现方式包括:

  • 多线程:每个I/O操作分配一个线程处理。
  • 事件驱动:使用事件循环处理I/O事件,例如selectpollepoll等。
3.2 高效并发编程

多线程网络编程

  • 线程同步:避免多个线程同时访问共享资源,使用互斥锁、条件变量等。
  • 线程池:复用线程,减少线程创建和销毁的开销,提高性能。

实例:使用线程池处理多个客户端连接。

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>#define PORT 8080std::mutex mtx;  // 互斥锁用于保护共享资源
std::condition_variable cv;  // 条件变量用于线程间同步
std::queue<int> clients;  // 用于存储待处理的客户端套接字// 处理客户端连接的函数
void handle_client(int client_sock) {char buffer[1024];int n = recv(client_sock, buffer, sizeof(buffer), 0);  // 接收客户端消息if (n > 0) {buffer[n] = '\0';  // 添加字符串终止符std::cout << "Received: " << buffer << std::endl;const char* response = "Message received";send(client_sock, response, strlen(response), 0);  // 发送响应给客户端}close(client_sock);  // 关闭客户端连接
}// 工作线程函数,用于处理客户端连接
void worker() {while (true) {int client_sock;{std::unique_lock<std::mutex> lock(mtx);  // 获取锁cv.wait(lock, [] { return !clients.empty(); });  // 等待条件变量通知client_sock = clients.front();  // 从队列中取出客户端套接字clients.pop();  // 移除队列中的套接字}handle_client(client_sock);  // 处理客户端连接}
}int main() {int server_sock = socket(AF_INET, SOCK_STREAM, 0);  // 创建TCP套接字if (server_sock < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;  // 使用IPv4server_addr.sin_addr.s_addr = INADDR_ANY;  // 绑定所有可用的网络接口server_addr.sin_port = htons(PORT);  // 绑定端口if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind failed");close(server_sock);exit(EXIT_FAILURE);}if (listen(server_sock, 5) < 0) {  // 设置监听队列的最大长度为5perror("listen failed");close(server_sock);exit(EXIT_FAILURE);}// 创建多个工作线程std::vector<std::thread> workers;for (int i = 0; i < 4; ++i) {workers.emplace_back(worker);  // 启动工作线程}while (true) {struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr);int client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_len);  // 接受客户端连接if (client_sock < 0) {perror("accept failed");continue;}{std::lock_guard<std::mutex> lock(mtx);  // 获取锁clients.push(client_sock);  // 将客户端套接字添加到队列中}cv.notify_one();  // 通知一个工作线程}for (auto& t : workers) {t.join();  // 等待所有工作线程结束}close(server_sock);  // 关闭服务器套接字return 0;
}

 

3.3 使用Boost.Asio进行异步编程

Boost.Asio 是一个强大且灵活的库,提供了跨平台的异步I/O操作,支持多平台。我们继续讨论如何使用Boost.Asio实现一个高效的异步TCP服务器。

完整代码示例:使用Boost.Asio进行异步TCP服务器

BoostServer.cpp
#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <utility>using boost::asio::ip::tcp;// 会话类,用于管理单个客户端连接
class Session : public std::enable_shared_from_this<Session> {
public:explicit Session(tcp::socket socket): socket_(std::move(socket)) {}// 开始会话void start() {do_read();  // 开始读取数据}private:// 异步读取数据void do_read() {auto self(shared_from_this());socket_.async_read_some(boost::asio::buffer(data_, max_length),[this, self](boost::system::error_code ec, std::size_t length) {if (!ec) {std::cout << "Received: " << data_ << std::endl;do_write(length);  // 读取完成后写入数据}});}// 异步写入数据void do_write(std::size_t length) {auto self(shared_from_this());boost::asio::async_write(socket_, boost::asio::buffer(data_, length),[this, self](boost::system::error_code ec, std::size_t /*length*/) {if (!ec) {do_read();  // 写入完成后继续读取数据}});}tcp::socket socket_;  // 套接字enum { max_length = 1024 };char data_[max_length];  // 数据缓冲区
};// 服务器类,用于管理客户端连接
class Server {
public:Server(boost::asio::io_context& io_context, short port): acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {do_accept();  // 开始接受连接}private:// 异步接受连接void do_accept() {acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket) {if (!ec) {std::make_shared<Session>(std::move(socket))->start();}do_accept();  // 继续接受下一次连接});}tcp::acceptor acceptor_;  // 接受器,用于监听连接
};int main(int argc, char* argv[]) {try {if (argc != 2) {std::cerr << "Usage: BoostServer <port>\n";return 1;}boost::asio::io_context io_context;  // IO上下文Server s(io_context, std::atoi(argv[1]));  // 创建服务器io_context.run();  // 运行IO上下文} catch (std::exception& e) {std::cerr << "Exception: " << e.what() << "\n";}return 0;
}

 

解析

  1. Session类:管理单个客户端连接。
    • do_read:异步读取数据,使用async_read_some方法。
    • do_write:异步写入数据,使用async_write方法。
  2. Server类:管理所有客户端连接。
    • do_accept:异步接受新的连接,使用async_accept方法。
  3. main函数:创建io_contextServer实例,调用io_context.run()运行事件循环。

四、核心技术及高级话题

4.1 同步I/O与异步I/O的选择

同步I/O

  • 简单直接,易于编程和调试。
  • 适合处理少量并发连接。

异步I/O

  • 提高并发性能,适合高并发场景。
  • 编程复杂度较高,需要处理回调、状态管理等。
4.2 多线程与事件驱动模型

多线程模型

  • 每个连接分配一个线程处理。
  • 线程同步开销大,线程数量有限制。

事件驱动模型

  • 使用事件循环处理I/O事件。
  • 无需大量线程,仅需少量线程处理所有连接。
4.3 高效网络编程的关键技术
  • I/O复用:如selectpollepoll,实现单线程高效处理多个连接。
  • 零拷贝:减少内存拷贝,提高数据传输效率。
  • 内存池:复用内存,减少内存分配和释放开销。
  • 负载均衡:分配连接到不同服务器,均衡负载,提高系统吞吐量。
4.4 使用C++11/14/17/20新特性优化网络编程
  • 智能指针:如std::shared_ptrstd::unique_ptr,管理动态内存,避免内存泄漏。
  • lambda表达式:简化回调函数编写。
  • std::thread:标准多线程库,简化线程创建和管理。
  • std::async:异步任务执行,简化异步编程。

五、实例:高效异步HTTP服务器

5.1 异步HTTP服务器

使用Boost.Asio实现一个高效的异步HTTP服务器:

#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <utility>using boost::asio::ip::tcp;class HttpSession : public std::enable_shared_from_this<HttpSession> {
public:explicit HttpSession(tcp::socket socket): socket_(std::move(socket)) {}void start() {do_read();}private:void do_read() {auto self(shared_from_this());socket_.async_read_some(boost::asio::buffer(buffer_),[this, self](boost::system::error_code ec, std::size_t length) {if (!ec) {handle_request(length);}});}void handle_request(std::size_t length) {std::string data(buffer_.data(), length);std::cout << "Request: " << data << std::endl;std::string response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";auto self(shared_from_this());boost::asio::async_write(socket_, boost::asio::buffer(response),[this, self](boost::system::error_code ec, std::size_t /*length*/) {if (!ec) {socket_.shutdown(tcp::socket::shutdown_both, ec);}});}tcp::socket socket_;std::array<char, 8192> buffer_;
};class HttpServer {
public:HttpServer(boost::asio::io_context& io_context, short port): acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {do_accept();}private:void do_accept() {acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket) {if (!ec) {std::make_shared<HttpSession>(std::move(socket))->start();}do_accept();});}tcp::acceptor acceptor_;
};int main(int argc, char* argv[]) {try {if (argc != 2) {std::cerr << "Usage: HttpServer <port>\n";return 1;}boost::asio::io_context io_context;HttpServer server(io_context, std::atoi(argv[1]));io_context.run();} catch (std::exception& e) {std::cerr << "Exception: " << e.what() << "\n";}return 0;
}

 

解析

  1. HttpSession类:管理单个HTTP会话。
    • do_read:异步读取HTTP请求。
    • handle_request:处理HTTP请求,生成响应。
    • do_write:异步发送HTTP响应。
  2. HttpServer类:管理所有HTTP会话。
    • do_accept:异步接受新的HTTP连接。
  3. main函数:创建io_contextHttpServer实例,调用io_context.run()运行事件循环。

运行结果

  1. 启动HTTP服务器:

    ./HttpServer 8080
    
  2. 使用浏览器或curl访问服务器:

    curl http://localhost:8080

         输出

Hello, world!

六、拓展思考

1、套接字(Socket)是什么?它包括哪些核心内容?

套接字(Socket)是计算机网络编程中一个重要的概念,它提供了一种通信的抽象,使得程序可以通过网络进行数据传输。套接字在应用层和传输层之间起到了桥梁作用,使得不同主机上的应用程序能够进行通信。换句话说,套接字是网络通信的端点,负责处理网络协议栈中的底层细节。

套接字的定义

套接字是一个网络编程接口,允许程序发送和接收数据,通过IP地址和端口号唯一标识网络中的通信端点。套接字可以基于多种传输协议进行操作,最常见的有TCP(传输控制协议)和UDP(用户数据报协议)。

套接字的核心内容

套接字编程涉及多个核心概念和操作步骤,下面详细介绍这些内容:

1. 套接字类型
  • SOCK_STREAM:使用TCP协议,提供可靠的面向连接的通信。
  • SOCK_DGRAM:使用UDP协议,提供不可靠的无连接的通信。
  • SOCK_RAW:使用原始套接字,允许直接访问底层协议,如IP协议,通常用于网络测试和低层次的网络编程。
2. 地址族
  • AF_INET:IPv4地址族。
  • AF_INET6:IPv6地址族。
  • AF_UNIX:本地通信的Unix套接字。
3. 套接字的基本操作
  • 创建套接字:使用socket()系统调用创建一个套接字。
  • 绑定地址:使用bind()将套接字绑定到本地地址和端口。
  • 监听(仅用于TCP服务器):使用listen()将套接字置于监听模式,等待客户端连接。
  • 接受连接(仅用于TCP服务器):使用accept()接受客户端连接,返回新的套接字用于通信。
  • 连接(仅用于TCP客户端):使用connect()将套接字连接到服务器地址。
  • 发送数据:使用send()sendto()发送数据。
  • 接收数据:使用recv()recvfrom()接收数据。
  • 关闭套接字:使用close()关闭套接字,释放资源。
套接字的高级内容
  • 非阻塞模式:套接字可以设置为非阻塞模式,使得I/O操作不会阻塞程序执行。
  • 多线程/多进程:使用多线程或多进程处理多个客户端连接,提高并发性能。
  • 异步I/O:使用异步I/O操作,如selectpollepoll或Boost.Asio,实现高效的事件驱动编程。
  • 安全套接字:使用SSL/TLS加密通信,确保数据传输的安全性。

概括总结

        套接字(Socket)是网络编程中关键的抽象和接口,提供了通过网络进行数据传输的基本功能。理解和掌握套接字的核心内容和操作步骤是进行网络编程的基础。通过深入学习和实践,开发者可以灵活地使用套接字进行各种网络应用的开发,从简单的客户端-服务器通信到复杂的分布式系统。

 

2、套接字 socket是基于哪个网络协议的?是TCP还是Http?

        套接字(Socket)是一种网络编程的抽象,提供了一种通用的接口,使得程序能够灵活地使用不同的网络协议进行通信。套接字并不局限于某一种协议,可以基于TCP(SOCK_STREAM)或UDP(SOCK_DGRAM)等多种协议进行操作。HTTP协议是一种应用层协议,通常运行在TCP套接字之上。通过掌握套接字编程,可以实现各种网络应用,从简单的客户端-服务器通信到复杂的分布式系统。

总结

        本文深入探讨了C++网络编程中的套接字(Socket)开发技术,详细讲解了其概念、底层原理、网络协议知识、本质及需要掌握的核心点,并通过经典实例进行解析。我们介绍了同步与异步I/O、多线程与事件驱动模型、高效网络编程的关键技术,最后详细展示了如何使用Boost.Asio实现一个高效的异步HTTP服务器。通过这些技术和示例代码,高级C++开发者可以深入理解和掌握网络编程的关键技术,为开发高效、可扩展的网络应用打下坚实的基础。希望这些代码和注释能够帮助你更好地理解和应用C++网络编程。

相关文章:

学懂C++(三十八):深入详解C++网络编程:套接字(Socket)开发技术

目录 一、概述与基础概念 1.1 套接字&#xff08;Socket&#xff09;概念 1.2 底层原理与网络协议 1.2.1 网络协议 1.2.2 套接字工作原理 二、C套接字编程核心技术 2.1 套接字编程的基本步骤 2.2 套接字编程详细实现 2.2.1 创建套接字 2.2.2 绑定地址 2.2.3 监听和接…...

SpringBoot-配置加载顺序

目录 前言 样例 内部配置加载顺序 ​ 样例 小结 前言 我之前写的配置文件&#xff0c;都是放在resources文件夹&#xff0c;根据当前目录下&#xff0c;优先级的高低&#xff0c;判断谁先被加载。但实际开发中&#xff0c;我们写的配置文件并不是&#xff0c;都放…...

第八周:机器学习笔记

第八周机器学习笔记 摘要Abstract机器学习1. 鱼和熊掌和可兼得的机器学习1.1 Deep network v.s. Fat network 2. 为什么用来验证集结果还是不好&#xff1f; Pytorch学习1. 卷积层代码实战2. 最大池化层代码实战3. 非线性激活层代码实战 总结 摘要 本周学习对李宏毅机器学习视…...

音乐怎么剪切掉一部分?5个方法,轻松学会音频分割!(2024全新)

音乐怎么剪切掉一部分&#xff1f;音频文件是娱乐和创作的重要基础。音频在我们日常生活中发挥着重要作用&#xff0c;从音乐播放列表到有趣的视频&#xff0c;它无处不在。无论是音乐爱好者还是内容创作者&#xff0c;我们常常需要对音频文件进行剪切和编辑。想象一下&#xf…...

洛谷 CF295D Greg and Caves

题目来源于&#xff1a;洛谷 题目本质&#xff1a;动态规划dp&#xff0c;枚举 解题思路&#xff1a;将整个洞分成两半&#xff0c;一半递增&#xff0c;一半递减。我们分别 DP 求值&#xff0c;最后合并。状态转移方程为&#xff1a;dpi,j​k2∑j​(j−k1)dpi−1,k​1。枚举极…...

【图像处理】在图像处理算法开发中,有哪些常见的主观评价指标和客观评价指标?

主观评价指标 在图像处理算法开发中&#xff0c;主观评价指标依赖于观察者的个人感受和判断&#xff0c;通常用于评估图像的视觉质量。以下是一些常见的主观评价指标&#xff1a; 平均意见分数 (Mean Opinion Score, MOS)&#xff1a;通过收集多个评价者的评分并计算平均值来评…...

从零开始学cv-6:图像的灰度变换

文章目录 一&#xff0c;简介&#xff1a;二、图像的线性变换三、分段线性变换四&#xff0c;非线性变换4.1 对数变换4.2 Gamma变换 五&#xff0c;效果: 一&#xff0c;简介&#xff1a; 图像灰度变换涉及对图像中每个像素的灰度值执行数学运算&#xff0c;进而调整图像的视觉…...

使用Apache POI和POI-OOXML实现word模板文档自动填充功能

最近接到一个新的需求&#xff0c;用户创建好模板文件保存到模板库&#xff0c;然后使用在线文档编辑器打开模板时&#xff0c;将系统数据填充到模板文件并生成新的word文件&#xff0c;然后在线编辑&#xff0c;研究使用Apache POI和POI-OOXML实现了这个功能。 Maven依赖 <…...

【HarmonyOS NEXT星河版开发学习】综合测试案例-各平台评论部分

目录 前言 功能展示 整体页面布局 最新和最热 写评论 点赞功能 界面构建 初始数据的准备 列表项部分的渲染 底部区域 index部分 知识点概述 List组件 List组件简介 ListItem组件详解 ListItemGroup组件介绍 ForEach循环渲染 列表分割线设置 列表排列方向设…...

垂直行业数字化表现抢眼 亚信科技全年利润展望乐观

大数据产业创新服务媒体 ——聚焦数据 改变商业 2024年8月14日&#xff0c;亚信科技控股有限公司&#xff08;股票代码&#xff1a;01675.HK&#xff09;公布了公司截至2024年6月30日的中期业绩。 财报数据显示&#xff0c;2024年上半年&#xff0c;亚信科技的营业收入为人民币…...

EmguCV学习笔记 VB.Net 4.1 颜色变换

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 教程VB.net版本请访问&#xff1a;EmguCV学习笔记 VB.Net 目录-CSDN博客 教程C#版本请访问&#xff1a;EmguCV学习笔记 C# 目录-CSD…...

【MySQL进阶之路】表结构的操作

目录 创建表 查看表 查看数据库有哪些表 查看表结构 查看表的详细信息 修改表 表的重命名 添加一列 修改某一列的属性 删除某一列 对列进行重命名 删除表 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 【MySQL进阶之路】MySQL基础——从零认识MySQL-CSDN博客 创…...

3分钟搞定PDF转PPT!你一定要知道的3款转换神器!

在数字办公成为主流的当下&#xff0c;我们每天会收到各类基于数字化方式存储的办公文档&#xff0c;如PDF、PPT、Word、Excel文档等。 日常处理这些文档时&#xff0c;经常需要在不同格式的文档之间进行切换和转换&#xff0c;其中将PDF转换为PPT就是一个非常高频的需求&…...

【EasyExcel】导出excel-设置动态表头并导出数据

需求背景&#xff1a; 导出excel的设置某些表头动态导出(可以根据筛选条件或一些属性的数据量)&#xff0c;方便导出后用户查看想看的信息。 一、技术选型&#xff1a; easyExcel的原生数据处理 二、方案设计&#xff1a; 根据EasyExcel支持的表头List<List<String>…...

深入探索 Elasticsearch 8:新特性与核心原理剖析(上)

深入探索 Elasticsearch 8&#xff1a;新特性与核心原理剖析 目录 一、引言 &#xff08;二&#xff09;版本 8 的重要意义 二、Elasticsearch 8 的新特性 三、Elasticsearch 的核心原理 一、引言 &#xff08;一&#xff09;Elasticsearch 简介 在大数据处理和搜索领域…...

瑜伽馆预约小程序,在线预约,提高商业价值

随着大众生活质量的提高&#xff0c;对休闲运动的关注逐渐加大&#xff0c;瑜伽作为一种身心放松、改善体态的运动&#xff0c;深受女性用户的喜爱。目前&#xff0c;各大瑜伽馆开始结合数字化&#xff0c;建立了新型的线上小程序&#xff0c;帮助大众快速预约体验瑜伽&#xf…...

Python--数据类型转换

在Python中&#xff0c;数据类型的转换是一个常见的操作&#xff0c;涉及将一种数据类型转换为另一种数据类型。Python提供了多种内置函数用于执行这种转换&#xff0c;如 int()、str()、float()、list()、tuple()、set()、dict() 等。下面详细讨论Python的基本数据类型及它们之…...

域控ntdsutil修改架构、域命名、PDC、RID、结构主机

#笔记记录# FSMO盒修改 1、提示访问特权不够&#xff0c;不能执行该操作&#xff0c;0x2098 清除缓存账号密码并修改新架构管理员账号密码即可。 背景&#xff1a;更替架构主机、域命名主机 C:\Windows\system32>ntdsutil ntdsutil: roles fsmo maintenance: ?? …...

解决 Swift 6 全局变量不能满足并发安全(concurrency-safe)读写的问题

概述 WWDC 24 终于在 Swift 十岁生日发布了全新的 Swift 6。这不仅意味着 Swift 进入了全新的“大”版本时代&#xff0c;而且 Swift 编译器终于做到了并发代码执行的“绝对安全”。 不过&#xff0c;从 Swift 5 一步迈入“新时代”的小伙伴们可能对新的并发检查有些许“水土不…...

迈入退休生活,全职开发ue独立游戏上架steam

决定退休了。算了算睡后收入&#xff0c;也可以达到每月一万一&#xff0c;正好可以养家糊口。 既然退休了&#xff0c;那就做些想做的事情&#xff0c;别人养花养草&#xff0c;而我打算开发独立游戏上架steam。 一&#xff0c;盘点下目前的技术体系。 1&#xff0c;图形学底…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...