WIN32_LEAN_AND_MEAN
- 一个预处理宏,用于控制
Windows头文件中包含哪些内容- 具体来说,定义这个宏会减少 Windows 头文件中包含的一些不常用的头文件和
API,从而减小编译时间并减少编译产生的二进制文件的大小 - 比如在包含
windows.h之前定义了WIN32_LEAN_AND_MEAN,一些较少使用的头文件和API(如WinSockets、Cryptographic API、Windows帮助等)就不会被包含进来
- 具体来说,定义这个宏会减少 Windows 头文件中包含的一些不常用的头文件和
|
1 2 |
#define WIN32_LEAN_AND_MEAN // 定义这个宏以减小头文件尺寸和编译时间 #include <windows.h> |
MAKEWORD
- 用于将两个字节(一个字节为
8位)组合成一个WORD(一个WORD是16位) - 主要用于初始化
Winsock库的版本
关于版本
- 可能包括:
Winsock 1.1Winsock 2.0Winsock 2.1Winsock 2.2
- 实际应用中,一般会使用
2.2版本,因为它提供了最全面的功能支持,并且向下兼容到更早的版本 - 某些操作系统版本中可能只支持特定的
Winsock版本Windows 95和Windows 98通常只支持到Winsock 1.1- 而
Windows XP和更高版本通常会支持Winsock 2.0甚至更高
- 返回值
- 使用
WSAStartup函数初始化Winsock库时,如果请求的版本不受支持,该函数会返回错误
- 使用
recv返回值
解析
|
1 2 3 4 5 6 7 |
int len = recv(client_sock, (char*)&header, sizeof(header), 0); if (en > 0) { } else if (len == 0) { } else { if (errno == ECONNRESET) { } else {} } |
- 接收到数据,返回值是正值
- 客户端正常关闭连接,返回值是
0 - 客户端被强制结束了或网络故障,返回值是
-1
errno
errno是一个全局变量,用于许多C和C++的标准库函数来指示特定的错误情况- 这些函数遇到错误时,它们通常会返回一个错误代码(例如
-1或NULL),并设置errno以提供有关错误的更多信息
- 这些函数遇到错误时,它们通常会返回一个错误代码(例如
- 主要用途是提供关于系统调用和某些库函数失败原因的更详细信息
- 详细值:
EACCES: 权限被拒绝EAGAIN或EWOULDBLOCK: 资源暂时不可用EBADF: 错误的文件描述符ECONNRESET: 对端重置了连接EINTR: 被信号中断EINVAL: 无效的参数ENOMEM: 没有足够的内存ENOTSOCK: 描述符不是一个socket
- 正确的使用方法:
|
1 2 3 4 5 |
errno = 0; int result = some_function(); if (result == -1 && errno != 0) { perror("An error occurred"); } |
- 在
Windows上,errno不是主要用于标识WinSock错误的机制- 当使用
WinSock API(如recv)时,你应该使用WSAGetLastError函数来获取错误代码
- 当使用
WSAGetLastError
- 函数返回上一个
WinSock函数调用的错误代码- 这与标准
C库中的errno变量有点相似,但它是专门为WinSock设计的
- 这与标准
- 常见错误代码:
WSAEACCES: 试图访问一个受权限保护的socketWSAECONNRESET: 对端执行了一个resetWSAEWOULDBLOCK: 非阻塞操作没有立即完成WSAENOTSOCK: 描述符不是一个socketWSAETIMEDOUT: 连接尝试没有成功,或连接已断开,因为连接相关的活动没有在给定的时间段内完成
- 示例:
|
1 2 3 4 5 6 |
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { int error = WSAGetLastError(); printf("Socket creation failed with error: %d\n", error); // 进一步处理错误... } |
- 想为错误代码获取描述性的错误消息,你可以使用
FormatMessage函数
FormatMessage
- 在
Windows编程中遇到一个错误代码,如GetLastError或WSAGetLastError返回的代码,可以使用FormatMessage来得到该错误代码对应的描述性错误消息- 这个函数可以从系统的错误代码表中检索本地化的错误消息描述,或者从用户定义的消息表资源中检索消息
- 示例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
DWORD error = GetLastError(); LPVOID errMsgBuffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, // Default language (LPWSTR) &errMsgBuffer, 0, NULL ); wprintf(L"Error %d: %s\n", error, errMsgBuffer); LocalFree(errMsgBuffer); // 释放由 FormatMessage 分配的内存 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
LPVOID errMsgBuffer; DWORD err_len = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, // Default language (LPWSTR)&errMsgBuffer, 0, NULL); LPWSTR lpMsgStr = (LPWSTR)errMsgBuffer; std::wstring result(lpMsgStr, lpMsgStr + err_len); std::locale::global(std::locale("")); std::wcout << result << std::endl; LocalFree(errMsgBuffer); if (error == WSAECONNRESET) { std::cout << "connection reset by client." << std::endl; } else { std::cout << "recv failed." << std::endl; } |
- 控制台编码不对时,会导致显示中文乱码
|
1 |
std::locale::global(std::locale("")); |
std::locale
- 当你设置全局
locale使用std::locale::global(std::locale(""));后,它会在程序的整个运行期间有效,除非你再次更改它 - 这个设置将会影响所有使用标准C++库和全局locale设置的函数和对象
- 例如,这将影响到输入/输出流(如
std::cout和std::cin)、字符串格式化和解析函数,以及其他任何依赖locale的操作
- 例如,这将影响到输入/输出流(如
- 在多线程环境中,
std::locale::global的行为可能不是线程安全的- 这意味着如果你在一个线程中更改了它,其他线程可能会受到未预期的影响
线程局部local
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
thread_local std::locale myLocale; void workerFunction(int id) { // Set thread-specific locale if (id % 2 == 0) { myLocale = std::locale("en_US.UTF-8"); std::cout << "Thread " << id << " set locale to en_US.UTF-8\n"; } else { myLocale = std::locale("fr_FR.UTF-8"); std::cout << "Thread " << id << " set locale to fr_FR.UTF-8\n"; } } int main() { std::thread t1(workerFunction, 1); std::thread t2(workerFunction, 2); t1.join(); t2.join(); return 0; } |
- 当一个变量被声明为
thread_local时,每个线程都会为该变量创建一个单独的存储区域,这与全局变量或静态变量不同- 当一个线程修改其版本的
myLocale时,它不会影响到其他线程中的myLocale实例
- 当一个线程修改其版本的
thread_local可以用于任何数据类型,包括基本类型、对象、指针、数组等- 关键是这些变量的每个线程都有其独立的实例
- 当线程开始时,
thread_local变量会按照它们的声明顺序进行初始化
当线程结束时,它们会按照与声明相反的顺序进行销毁 - 不是所有的编译器和平台都完全支持
thread_local- 所以在使用之前,请确保你的开发环境支持这一特性
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Shell 语法记述 第二篇09/05
- ♥ breakpad记述:Windows下静态库的编译使用03/15
- ♥ C++并发编程 _管理线程05/07
- ♥ Linux » Linux 高性能服务器编程:信号12/12
- ♥ C++数据库_Sqlite306/23
- ♥ Windows_API_Apply_112/31