首页 > 系统相关 >突破编程_C++_网络编程(Windows 套接字(阻塞模式与非阻塞模式))

突破编程_C++_网络编程(Windows 套接字(阻塞模式与非阻塞模式))

时间:2024-04-10 19:59:16浏览次数:29  
标签:error 编程 阻塞 模式 result printf 接字

1 阻塞模式与非阻塞模式的概念

(1)阻塞模式

  1. 概念: 在阻塞模式下,当套接字执行I/O操作时,如果操作不能立即完成,调用函数会一直等待直到操作完成。在等待期间,执行操作的线程会被阻塞,无法继续执行其他任务。

  2. 特点:

  • 简单直观:对于许多简单的网络应用来说,阻塞模式编程简单直观,易于理解和实现。
  • 资源消耗:由于线程在等待 I/O 操作完成时被阻塞,可能会导致资源的浪费,特别是在高并发场景下。
  • 效率:在阻塞模式下,线程在等待 I/O 操作完成时会处于空闲状态,这可能会降低程序的执行效率。
  1. 应用场景: 阻塞模式适用于那些对实时性要求不高,且I/O操作不频繁的场景。

(2)非阻塞模式

  1. 概念: 非阻塞模式下,套接字在执行 I/O 操作时,无论操作是否完成,调用函数都会立即返回。即使操作没有完成,线程也不会被阻塞,可以继续执行其他任务。

  2. 特点:

  • 高效性:非阻塞模式允许线程在等待 I/O 操作完成的同时执行其他任务,提高了程序的执行效率。
  • 编程复杂度:由于非阻塞模式下,函数会在操作未完成时立即返回,因此需要程序员自行处理轮询和重试的逻辑,增加了编程的复杂度。
  • 资源消耗:虽然非阻塞模式可以提高线程利用率,但在高并发场景下,频繁的轮询和重试可能会导致额外的CPU资源消耗。
  1. 应用场景: 非阻塞模式适用于那些对实时性要求高,且需要处理大量并发 I/O 操作的场景,如服务器端的网络编程。

2 阻塞模式套接字编程

2.1 阻塞模式的工作原理

Windows 套接字(Socket)的阻塞模式工作原理主要基于操作系统的 I/O 操作机制。在阻塞模式下,当一个套接字被调用执行 I/O 操作(如发送数据或接收数据)时,如果操作不能立即完成,调用线程将会被挂起,直到操作完成为止。

具体来说,当调用如 send、recv 等函数时,如果此时套接字的缓冲区没有足够的空间来发送数据,或者没有数据可读来接收,那么调用这些函数的线程将会被阻塞。操作系统会将这个线程置于等待状态,并释放CPU控制权给其他线程执行。直到所需的 I/O 操作完成(例如,数据发送完毕或接收到数据),操作系统才会唤醒这个被阻塞的线程,使其继续执行后续的代码。

这种阻塞模式的好处在于编程简单直观,开发者无需关心底层的 I/O 操作细节。然而,它也存在一些缺点。例如,在高并发场景下,大量的线程可能因为等待 I/O 操作而被阻塞,导致 CPU 资源得不到充分利用,进而可能影响到程序的性能。

此外,值得注意的是,并不是所有的 Windows Sockets API 函数在阻塞模式下都会发生阻塞。例如,当以阻塞模式的套接字为参数调用 bind、listen 等函数时,它们会立即返回,因为这些操作并不涉及到实际的 I/O 数据传输。

2.2 阻塞模式下的发送与接收操作

(1)发送操作

在阻塞模式下,当调用发送函数(如 send、WSASend 等)时,线程会等待直到数据完全发送或发生错误。如果套接字的发送缓冲区已满,调用线程将被阻塞,直到有足够的空间可供发送数据。这意味着在发送大量数据或网络状况不佳时,线程可能会被阻塞一段时间。

(2)接收操作

同样地,在阻塞模式下执行接收操作(如 recv、WSARecv 等)时,线程会等待直到有数据可读或发生错误。如果套接字的接收缓冲区为空,调用线程将被阻塞,直到有数据到达。这意味着在没有数据到达或网络延迟较高时,接收操作的线程也会处于阻塞状态。

(3)注意事项

  • 线程管理:由于阻塞模式下线程可能会被阻塞,因此合理地管理线程是非常重要的。通常,可以将套接字 I/O 操作放在单独的线程中执行,以避免阻塞主线程。
  • 错误处理:在阻塞模式下,如果发送或接收操作失败,会返回错误代码。因此,需要适当地处理这些错误,比如重试发送、关闭套接字或通知用户等。
  • 性能考虑:在高并发或需要快速响应的场景中,阻塞模式可能会导致性能问题。此时,可以考虑使用非阻塞模式或异步 I/O 来提高性能。

2.3 阻塞模式套接字编程示例

在 Windows 套接字编程中,阻塞模式是最常见的操作模式,也是默认模式。以下是一个简单的阻塞模式编程示例,包括服务端和客户端的创建、连接和数据发送/接收。

(1)服务端示例

#include <winsock2.h>  
#include <stdio.h>  

#pragma comment(lib, "ws2_32.lib")  

int main() {
	WSADATA wsaData;
	SOCKET serverSocket, clientSocket;
	struct sockaddr_in serverAddr, clientAddr;
	int addrSize = sizeof(clientAddr);
	char buffer[1024];
	int result;

	// 初始化Winsock库  
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("WSAStartup failed: %d\n", WSAGetLastError());
		return 1;
	}

	// 创建套接字  
	serverSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (serverSocket == INVALID_SOCKET) {
		printf("Could not create socket: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 设置服务器地址信息  
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = INADDR_ANY;
	serverAddr.sin_port = htons(12345);

	// 绑定套接字到服务器地址  
	if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		printf("Bind failed with error: %d\n", WSAGetLastError());
		closesocket(serverSocket);
		WSACleanup();
		return 1;
	}

	// 开始监听连接请求  
	if (listen(serverSocket, 5) == SOCKET_ERROR) {
		printf("Listen failed with error: %d\n", WSAGetLastError());
		closesocket(serverSocket);
		WSACleanup();
		return 1;
	}

	// 接受客户端连接  
	clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &addrSize);
	if (clientSocket == INVALID_SOCKET) {
		printf("Accept failed with error: %d\n", WSAGetLastError());
		closesocket(serverSocket);
		WSACleanup();
		return 1;
	}

	// 接收数据  
	result = recv(clientSocket, buffer, sizeof(buffer), 0);
	if (result > 0) {
		buffer[result] = '\0';
		printf("Received: %s\n", buffer);
	}
	else {
		printf("recv failed with error: %d\n", WSAGetLastError());
	}

	// 发送响应  
	send(clientSocket, "Hello from server!", strlen("Hello from server!"), 0);

	// 关闭套接字和Winsock库  
	closesocket(clientSocket);
	closesocket(serverSocket);
	WSACleanup();

	return 0;
}

(2)客户端示例

#include <winsock2.h>  
#include <stdio.h>  

#pragma comment(lib, "ws2_32.lib")  

int main() {
	WSADATA wsaData;
	SOCKET clientSocket;
	struct sockaddr_in serverAddr;
	char buffer[1024];
	int result;

	// 初始化Winsock库  
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		printf("WSAStartup failed: %d\n", WSAGetLastError());
		return 1;
	}

	// 创建套接字  
	clientSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET) {
		printf("Could not create socket: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 设置服务器地址信息  
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 假设服务器运行在本地  
	serverAddr.sin_port = htons(12345);

	// 连接到服务器  
	if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		printf("Connect failed with error: %d\n", WSAGetLastError());
		closesocket(clientSocket);
		WSACleanup();
		return 1;
	}

	// 发送数据  
	send(clientSocket, "Hello from client!", strlen("Hello from client!"), 0);

	// 接收响应  
	result = recv(clientSocket, buffer, sizeof(buffer), 0);
	if (result > 0) {
		buffer[result] = '\0';
		printf("Received: %s\n", buffer);
	}
	else {
		printf("recv failed with error: %d\n", WSAGetLastError());
	}

	// 关闭套接字和Winsock库  
	closesocket(clientSocket);
	WSACleanup();

	return 0;
}

3 非阻塞模式套接字编程

3.1 非阻塞模式的工作原理

非阻塞模式工作原理主要基于事件驱动和异步通信。与阻塞模式不同,非阻塞模式允许套接字操作(如发送和接收数据)立即返回,而无需等待操作完成。这使得应用程序能够继续执行其他任务,而不是被阻塞在套接字操作上。

在非阻塞模式下,当调用 Windows 套接字API(如 send、recv 等)时,这些函数会立即返回,而不管操作是否完成。如果操作不能立即完成(例如,发送缓冲区已满或没有数据可读),函数将返回一个错误代码(如 WSAEWOULDBLOCK),而不是阻塞调用线程。这样,应用程序就可以继续执行其他任务,而不必等待套接字操作完成。

为了实现非阻塞模式下的通信,应用程序需要采取一种循环检查或事件通知的机制。例如,在接收数据时,应用程序可以不断调用recv函数,直到成功接收到数据或遇到错误为止。同样,在发送数据时,应用程序可能需要检查发送缓冲区的状态,以确保数据可以安全地发送。

此外,非阻塞模式还涉及到一些高级概念,如 I/O 完成端口(IOCP)和事件选择(select)机制。这些机制允许应用程序以更高效的方式处理多个套接字和并发 I/O 操作。例如,IOCP允许应用程序将套接字操作与特定的线程池关联起来,从而实现高效的并发处理。

需要注意的是,非阻塞模式虽然提高了应用程序的响应性和并发性能,但也增加了编程的复杂性。应用程序需要负责处理错误、超时、数据重排等问题,以确保通信的正确性和可靠性。

3.2 将套接字设置为非阻塞模式

在 Windows 平台上,将套接字设置为非阻塞模式涉及到使用 ioctlsocket 函数来修改套接字的行为。以下是如何将已创建的套接字设置为非阻塞模式的步骤:

  • 首先,创建一个套接字。
  • 然后使用 ioctlsocket 函数和 FIONBIO 标志来设置套接字为非阻塞模式。

以下是一个简单的示例,展示了如何设置套接字为非阻塞模式:

#include <winsock2.h>  
#include <stdio.h>  

#pragma comment(lib, "ws2_32.lib")  

int main() {
	WSADATA wsaData;
	SOCKET socketDescriptor;
	u_long nonblocking = 1;
	int result;

	// 初始化Winsock库  
	result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		printf("WSAStartup failed: %d\n", result);
		return 1;
	}

	// 创建套接字  
	socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
	if (socketDescriptor == INVALID_SOCKET) {
		printf("Could not create socket: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 设置套接字为非阻塞模式  
	result = ioctlsocket(socketDescriptor, FIONBIO, &nonblocking);
	if (result == SOCKET_ERROR) {
		printf("Could not set socket to non-blocking mode: %d\n", WSAGetLastError());
		closesocket(socketDescriptor);
		WSACleanup();
		return 1;
	}

	// 在这里你可以继续使用socketDescriptor进行连接、发送和接收操作  
	// ...  

	// 关闭套接字和清理Winsock库  
	closesocket(socketDescriptor);
	WSACleanup();

	return 0;
}

在上面的代码中,FIONBIO 是一个特殊的命令,它告诉 ioctlsocket 函数要修改套接字的阻塞模式。nonblocking变量设置为1,表示我们要将套接字设置为非阻塞模式。如果 ioctlsocket 函数返回 SOCKET_ERROR,则表示设置失败,我们可以检查 WSAGetLastError 函数返回的错误代码来了解失败的原因。

一旦套接字被设置为非阻塞模式,你就可以调用 connect、send、recv 等函数,它们会立即返回,而不会阻塞调用线程。如果操作不能立即完成,它们会返回一个错误代码,通常是 WSAEWOULDBLOCK。

3.3 非阻塞模式下的发送与接收操作

在Windows套接字非阻塞模式下,发送和接收操作将立即返回,无论操作是否完成。如果数据无法立即发送或接收,这些操作会返回一个错误代码,通常是WSAEWOULDBLOCK,表示操作被阻塞了,需要稍后再试。

以下是在非阻塞模式下执行发送和接收操作的基本步骤:

(1)发送数据

SOCKET socketDescriptor; // 假设已经创建了非阻塞套接字  
char *sendBuffer = "Hello, server!";  
int sendLength = strlen(sendBuffer);  
int bytesSent;  
  
// 尝试发送数据  
bytesSent = send(socketDescriptor, sendBuffer, sendLength, 0);  
if (bytesSent == SOCKET_ERROR) {  
    int error = WSAGetLastError();  
    if (error == WSAEWOULDBLOCK) {  
        // 数据当前无法发送,稍后再试  
        printf("Data could not be sent immediately, would block.\n");  
    } else {  
        // 发送失败,出现其他错误  
        printf("Send failed with error: %d\n", error);  
    }  
} else {  
    // 数据已成功发送部分或全部  
    printf("Sent %d bytes.\n", bytesSent);  
}

(2)接收数据

char recvBuffer[1024];  
int bytesReceived;  
  
// 尝试接收数据  
bytesReceived = recv(socketDescriptor, recvBuffer, sizeof(recvBuffer) - 1, 0);  
if (bytesReceived > 0) {  
    // 成功接收到数据  
    recvBuffer[bytesReceived] = '\0'; // 确保字符串以null结尾  
    printf("Received: %s\n", recvBuffer);  
} else if (bytesReceived == 0) {  
    // 连接已关闭,对方发送了EOF(通常是通过shutdown或close实现的)  
    printf("Connection closed by peer.\n");  
} else {  
    int error = WSAGetLastError();  
    if (error == WSAEWOULDBLOCK) {  
        // 当前没有数据可接收,稍后再试  
        printf("No data to receive, would block.\n");  
    } else {  
        // 接收失败,出现其他错误  
        printf("Recv failed with error: %d\n", error);  
    }  
}

在非阻塞模式下,如果 send 或 recv 返回 WSAEWOULDBLOCK,则应用程序需要稍后再次尝试发送或接收数据。这通常涉及到在应用程序中使用某种形式的循环或事件驱动机制来定期检查套接字的状态。

此外,非阻塞套接字编程通常还需要处理其他情况,例如部分数据发送或接收、错误处理以及超时等。在实际应用中,可能还需要使用更高级的技术,如 I/O 完成端口(IOCP)或事件选择(select)机制,以便更有效地处理多个套接字和并发 I/O 操作。

3.4 非阻塞模式套接字编程示例

(1)服务端示例

#include <stdio.h>  
#include <winsock2.h>  
#include <mswsock.h> // For ioctlsocket  
#include <string>  
#include <iostream>  

#pragma comment(lib, "ws2_32.lib")  

#define PORT 12345  
#define BUFFER_SIZE 1024  

int main() {
	WSADATA wsaData;
	SOCKET listenSocket, clientSocket;
	struct sockaddr_in serverAddr;
	int result;
	char recvBuffer[BUFFER_SIZE];
	fd_set readfds;
	struct timeval timeout;
	int ioctlResult;
	u_long iMode = 1; // Enable non-blocking mode  

	// 初始化Winsock库  
	result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		printf("WSAStartup failed with error: %d\n", result);
		return 1;
	}

	// 创建套接字  
	listenSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (listenSocket == INVALID_SOCKET) {
		printf("Socket creation failed with error: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 将套接字设置为非阻塞模式  
	ioctlResult = ioctlsocket(listenSocket, FIONBIO, &iMode);
	if (ioctlResult == SOCKET_ERROR) {
		printf("Failed to set socket to non-blocking mode: %d\n", WSAGetLastError());
		closesocket(listenSocket);
		WSACleanup();
		return 1;
	}

	// 设置服务器地址信息  
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	serverAddr.sin_port = htons(PORT);

	// 绑定套接字到指定地址和端口  
	result = bind(listenSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if (result == SOCKET_ERROR) {
		printf("Bind failed with error: %d\n", WSAGetLastError());
		closesocket(listenSocket);
		WSACleanup();
		return 1;
	}

	// 开始监听连接请求  
	result = listen(listenSocket, SOMAXCONN);
	if (result == SOCKET_ERROR) {
		printf("Listen failed with error: %d\n", WSAGetLastError());
		closesocket(listenSocket);
		WSACleanup();
		return 1;
	}

	printf("Server listening on port %d...\n", PORT);

	// 主循环,等待并接受客户端连接  
	while (1) {
		FD_ZERO(&readfds);
		FD_SET(listenSocket, &readfds);
		timeout.tv_sec = 5; // 设置5秒超时  
		timeout.tv_usec = 0;

		// 使用select等待套接字变得可读  
		result = select(listenSocket + 1, &readfds, NULL, NULL, &timeout);
		if (result == SOCKET_ERROR) {
			printf("Select failed with error: %d\n", WSAGetLastError());
			break;
		}
		else if (result == 0) {
			// 超时,没有事件发生  
			printf("Timeout occurred, no incoming connections.\n");
			continue;
		}

		// 检查是否有新的连接请求  
		if (FD_ISSET(listenSocket, &readfds)) {
			clientSocket = accept(listenSocket, NULL, NULL);
			if (clientSocket == SOCKET_ERROR) {
				if (WSAGetLastError() != WSAEWOULDBLOCK) {
					printf("Accept failed with error: %d\n", WSAGetLastError());
				}
			}
			else {
				// 设置客户端套接字为非阻塞模式  
				ioctlResult = ioctlsocket(clientSocket, FIONBIO, &iMode);
				if (ioctlResult == SOCKET_ERROR) {
					printf("Failed to set client socket to non-blocking mode: %d\n", WSAGetLastError());
					closesocket(clientSocket);
					continue;
				}
				// 客户端连接已接受,可以在这里处理客户端请求
				printf("New client connected.\n");

				// 这里可以添加代码来处理客户端发送的数据  
							// ...  

				std::string msg;
				std::cin >> msg;
							// 关闭客户端套接字  
				closesocket(clientSocket);
			}
		}

		// 可以在这里添加代码来处理其他套接字(如果有的话)  
	}

	// 关闭监听套接字并清理Winsock  
	closesocket(listenSocket);
	WSACleanup();

	return 0;
}

(2)客户端示例

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <winsock2.h>  
#include <mswsock.h> // For ioctlsocket  

#pragma comment(lib, "ws2_32.lib")  

#define SERVER_PORT 12345  
#define SERVER_IP "127.0.0.1"  
#define BUFFER_SIZE 1024  

int main() {
	WSADATA wsaData;
	SOCKET clientSocket;
	struct sockaddr_in serverAddr;
	int result;
	char sendBuffer[BUFFER_SIZE];
	char recvBuffer[BUFFER_SIZE];
	u_long iMode = 1; // Enable non-blocking mode  

	// 初始化Winsock库  
	result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		printf("WSAStartup failed with error: %d\n", result);
		return 1;
	}

	// 创建套接字  
	clientSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET) {
		printf("Socket creation failed with error: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// 将套接字设置为非阻塞模式  
	result = ioctlsocket(clientSocket, FIONBIO, &iMode);
	if (result == SOCKET_ERROR) {
		printf("Failed to set socket to non-blocking mode: %d\n", WSAGetLastError());
		closesocket(clientSocket);
		WSACleanup();
		return 1;
	}

	// 设置服务器地址信息  
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
	serverAddr.sin_port = htons(SERVER_PORT);

	// 连接到服务器  
	result = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
	if (result == SOCKET_ERROR) {
		int error = WSAGetLastError();
		if (error != WSAEWOULDBLOCK) {
			printf("Connect failed with error: %d\n", error);
			closesocket(clientSocket);
			WSACleanup();
			return 1;
		}
		else {
			printf("Connect is in progress...\n");
		}
	}
	else {
		printf("Connected to server successfully.\n");
	}

	// 发送数据到服务器  
	strcpy(sendBuffer, "Hello, server!");
	result = send(clientSocket, sendBuffer, strlen(sendBuffer), 0);
	if (result == SOCKET_ERROR) {
		int error = WSAGetLastError();
		if (error != WSAEWOULDBLOCK) {
			printf("Send failed with error: %d\n", error);
		}
		else {
			printf("Send would block, retrying later...\n");
		}
	}
	else {
		printf("Sent %d bytes to server.\n", result);
	}

	// 接收来自服务器的数据  
	result = recv(clientSocket, recvBuffer, BUFFER_SIZE, 0);
	if (result > 0) {
		printf("Received %d bytes from server: %s\n", result, recvBuffer);
	}
	else if (result == 0) {
		printf("Server closed the connection.\n");
	}
	else {
		int error = WSAGetLastError();
		if (error != WSAEWOULDBLOCK) {
			printf("Recv failed with error: %d\n", error);
		}
		else {
			printf("No data available, retrying later...\n");
		}
	}

	// 关闭套接字并清理Winsock库  
	closesocket(clientSocket);
	WSACleanup();

	return 0;
}

(3)输出

服务端的输出为:

Server listening on port 12345...
New client connected.

客户端的输出为:

Connect is in progress...
Sent 14 bytes to server.
No data available, retrying later...

标签:error,编程,阻塞,模式,result,printf,接字
From: https://blog.csdn.net/h8062651/article/details/137590979

相关文章

  • Python 更新 为什么要更新 Python? 如何更新 Python? 更新 Python 可能遇到的问题——《
    Python更新为什么要更新Python?如何更新Python?更新Python可能遇到的问题——《跟老吕学Python编程》附录资料Python更新为什么要更新Python?如何更新Python?更新Python可能遇到的问题总结Python更新最近的一次Python更新中,最引人瞩目的变化之一......
  • 3 突破编程_前端_SVG(rect 矩形)
    1rect元素的基本属性和用法在SVG中,<rect>元素用于创建矩形。<rect>元素有一些基本的属性,可以用来定义矩形的形状、位置、颜色等。以下是这些属性的详细解释:x和y:这两个属性定义矩形左上角的位置。x是矩形左上角到SVG画布左边缘的水平距离,y是矩形左上角到SVG画......
  • Java8 Stream API全面解析——高效流式编程的秘诀
    文章目录什么是StreamApi?快速入门流的操作创建流中间操作filter过滤map数据转换flatMap合并流distinct去重sorted排序limit限流skip跳过peek操作终结操作forEach遍历forEachOrdered有序遍历count统计数量min最小值max最大值reduce聚合collect收集anyM......
  • 小美的数组构造(美团2024届秋招笔试第二场编程真题)
    题面核心思想dp[i][j]表示前i个数字和为j时的组合数那么第i个数的取法有1<=k<=j需要遍历第i个数取k前i-1个数取j-k时dp[i][j]=(dp[i][j]+dp[i-1][j-k])%MOD;注意是和为j第i个数取k所以是dp[i][j]。同时需要判断第i个数不能和a数组取相同的......
  • HarmonyOS 开发-阻塞事件冒泡
    介绍本示例主要介绍在点击事件中,子组件enabled属性设置为false的时候,如何解决点击子组件模块区域会触发父组件的点击事件问题;以及触摸事件中当子组件触发触摸事件的时候,父组件如果设置触摸事件的话,如何解决父组件也会被触发的问题。效果图预览使用说明:开启使能开关,在点击事......
  • C++核心编程
    C++核心编程本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓。1内存分区模型C++程序在执行时,将内存大方向划分为4个区域代码区:存放函数体的二进制代码,由操作系统进行管理的全局区:存放全局变量和静态变量以及常量栈区:由编译器自动分配释放,存放......
  • 2024.4.10 OpenMP和MPI编程
    OpenMP和MPI编程OpenMP主要是在单机上进行并行,是基于共享内存的,共享内存就是多个核(包括单CPU多核和多CPU多核(都是单机))共享一个内存,只要是单台计算机都可以认为是共享内存,MP代表多线程的意思(Multi-Processing),其无法进行跨节点运算,并且OpenMP的库是默认集成在g++或者gcc里的;OpenMP......
  • 单例模式
    1、为什么使用单例(能解决什么问题)(1)处理资源访问冲突自定义实现了一个往文件中打印日志的Logger类。具体的代码实现如下所示:publicclassLogger{privateFileWriterwriter;publicLogger(){Filefile=newFile("/Users/wangzheng/log.txt");writer......
  • PROG2007编程总结
    评估简报PROG2007编程II职称评定2类型投资组合到期日4月8日星期一下午11:59AEST/AEDT(第6周开始)长度NA权重60%学术诚信(限值见下文在GenAI使用允许)GenAI可用于此评估。请参阅下面的学术诚信部分,了解可接受的使用GenAI在此评估中。提交请参阅下面的提交部分,了解如何提交您的看法单元......
  • 基于C语言的面向对象设计模式(持续更新)
    前言首先这篇文章只是初步的尝试,不涉及过于高深的编程技巧;同时需要表明的是,面向对象只是一种思想,不局限于什么样的编程语言,不可否认的是基于面向对象特性而设计的语言确实要比面向过程式的语言更加容易进行抽象和统筹,可以说面向对象的设计模式可以很大程度上摆脱过程的实例,但要论......