iocp
Neicole ~~ 学习旅程
:)Come On, 不要停息,这世界仍充满着各种神秘色彩,等待着我们去探索!更高,更广,更全面的角度,让我们拥有着不一样的体验!
IOCP模型与网络编程
一。前言:
在老师分配任务(“尝试利用IOCP模型写出服务端和客户端的代码”)给我时,脑子一片空白,并不知道什么是IOCP模型,会不会是像软件设计模式里面的工厂模式,装饰模式之类的那些呢?嘿嘿,不过好像是一个挺好玩的东西,挺好奇是什么东西来的,又是一个新知识啦~于是,开始去寻找一大堆的资料,为这个了解做准备,只是呢,有时还是想去找一本书去系统地学习一下,毕竟网络的资料还是有点零散。话说,本人学习这个模型的基础是,写过一个简单的Socket服务器及客户端程序,外加一个简单的Socket单服务器对多客户端程序,懂一点点的操作系统原理的知识。于是,本着一个学习与应用的态度开始探究这个IOCP是个什么东西。
二。提出相关问题:
1. IOCP模型是什么?
2. IOCP模型是用来解决什么问题的?它为什么存在?
3. 使用IOCP模型需要用到哪些知识?
4. 如何使用IOCP模型与Socket网络编程结合起来?
5. 学会了这个模型以后与我之前写过的简单的socket程序主要有哪些不同点?
三。部分问题探究及解决:(绝大多数是个人理解,再加上个人是菜鸟,如果有什么不对的地方,欢迎指正)
1. 什么是IOCP?什么是IOCP模型?IOCP模型有什么作用?
1) IOCP(I/O Completion Port),常称I/O完成端口。
2) IOCP模型属于一种通讯模型,适用于(能控制并发执行的)高负载服务器的一个技术。
3) 通俗一点说,就是用于高效处理很多很多的客户端进行数据交换的一个模型。
4) 或者可以说,就是能异步I/O操作的模型。
5) 只是了解到这些会让人很糊涂,因为还是不知道它究意具体是个什么东东呢?
下面我想给大家看三个图:
第一个是IOCP的内部工作队列图。(整合于《IOCP本质论》文章,在英文的基础上加上中文对照)
第二个是程序实现IOCP模型的基本步骤。(整合于《深入解释IOCP》,加个人观点、理解、翻译)
第三个是使用了IOCP模型及没使用IOCP模型的程序流程图。(个人理解绘制)
2. IOCP的存在理由(IOCP的优点)及技术相关有哪些?
之前说过,很通俗地理解可以理解成是用于高效处理很多很多的客户端进行数据交换的一个模型,那么,它具体的优点有些什么呢?它到底用到了哪些技术了呢?在Windows环境下又如何去使用这些技术来编程呢?它主要使用上哪些API函数呢?呃~看来我真是一个问题多多的人,跟前面提出的相关问题变种延伸了不少的问题,好吧,下面一个个来解决。
1) 使用IOCP模型编程的优点
① 帮助维持重复使用的内存池。(与重叠I/O技术有关)
② 去除删除线程创建/终结负担。
③ 利于管理,分配线程,控制并发,最小化的线程上下文切换。
④ 优化线程调度,提高CPU和内存缓冲的命中率。
2) 使用IOCP模型编程汲及到的知识点(无先后顺序)
① 同步与异步
② 阻塞与非阻塞
③ 重叠I/O技术
④ 多线程
⑤ 栈、队列这两种基本的数据结构
3) 需要使用上的API函数
① 与SOCKET相关
1、链接套接字动态链接库:int WSAStartup(...);
2、创建套接字库: SOCKET socket(...);
3、绑字套接字: int bind(...);
4、套接字设为监听状态: int listen(...);
5、接收套接字: SOCKET accept(...);
6、向指定套接字发送信息:int send(...);
7、从指定套接字接收信息:int recv(...);
② 与线程相关
1、创建线程:HANDLE CreateThread(...);
③ 重叠I/O技术相关
1、向套接字发送数据: int WSASend(...);
2、向套接字发送数据包: int WSASendFrom(...);
3、从套接字接收数据: int WSARecv(...);
4、从套接字接收数据包: int WSARecvFrom(...);
④ IOCP相关
1、创建完成端口: HANDLE WINAPI CreateIoCompletionPort(...);
2、关联完成端口: HANDLE WINAPI CreateIoCompletionPort(...);
3、获取队列完成状态: BOOL WINAPI GetQueuedCompletionStatus(...);
4、投递一个队列完成状态:BOOL WINAPI PostQueuedCompletionStatus(...);
四。完整的简单的IOCP服务器与客户端代码实例:
- // IOCP_TCPIP_Socket_Server.cpp
- #include <WinSock2.h>
- #include <Windows.h>
- #include <vector>
- #include <iostream>
- using namespace std;
- #pragma comment(lib, "Ws2_32.lib") // Socket编程需用的动态链接库
- #pragma comment(lib, "Kernel32.lib") // IOCP需要用到的动态链接库
- /**
- * 结构体名称:PER_IO_DATA
- * 结构体功能:重叠I/O需要用到的结构体,临时记录IO数据
- **/
- const int DataBuffSize = 2 * 1024;
- typedef struct
- {
- OVERLAPPED overlapped;
- WSABUF databuff;
- char buffer[ DataBuffSize ];
- int BufferLen;
- int operationType;
- }PER_IO_OPERATEION_DATA, *LPPER_IO_OPERATION_DATA, *LPPER_IO_DATA, PER_IO_DATA;
- /**
- * 结构体名称:PER_HANDLE_DATA
- * 结构体存储:记录单个套接字的数据,包括了套接字的变量及套接字的对应的客户端的地址。
- * 结构体作用:当服务器连接上客户端时,信息存储到该结构体中,知道客户端的地址以便于回访。
- **/
- typedef struct
- {
- SOCKET socket;
- SOCKADDR_STORAGE ClientAddr;
- }PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
- // 定义全局变量
- const int DefaultPort = 6000;
- vector < PER_HANDLE_DATA* > clientGroup; // 记录客户端的向量组
- HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
- DWORD WINAPI ServerWorkThread(LPVOID CompletionPortID);
- DWORD WINAPI ServerSendThread(LPVOID IpParam);
- // 开始主函数
- int main()
- {
- // 加载socket动态链接库
- WORD wVersionRequested = MAKEWORD(2, 2); // 请求2.2版本的WinSock库
- WSADATA wsaData; // 接收Windows Socket的结构信息
- DWORD err = WSAStartup(wVersionRequested, &wsaData);
- if (0 != err){ // 检查套接字库是否申请成功
- cerr << "Request Windows Socket Library Error!\n";
- system("pause");
- return -1;
- }
- if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){// 检查是否申请了所需版本的套接字库
- WSACleanup();
- cerr << "Request Windows Socket Version 2.2 Error!\n";
- system("pause");
- return -1;
- }
- // 创建IOCP的内核对象
- /**
- * 需要用到的函数的原型:
- * HANDLE WINAPI CreateIoCompletionPort(
- * __in HANDLE FileHandle, // 已经打开的文件句柄或者空句柄,一般是客户端的句柄
- * __in HANDLE ExistingCompletionPort, // 已经存在的IOCP句柄
- * __in ULONG_PTR CompletionKey, // 完成键,包含了指定I/O完成包的指定文件
- * __in DWORD NumberOfConcurrentThreads // 真正并发同时执行最大线程数,一般推介是CPU核心数*2
- * );
- **/
- HANDLE completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (NULL == completionPort){ // 创建IO内核对象失败
- cerr << "CreateIoCompletionPort failed. Error:" << GetLastError() << endl;
- system("pause");
- return -1;
- }
- // 创建IOCP线程--线程里面创建线程池
- // 确定处理器的核心数量
- SYSTEM_INFO mySysInfo;
- GetSystemInfo(&mySysInfo);
- // 基于处理器的核心数量创建线程
- for(DWORD i = 0; i < (mySysInfo.dwNumberOfProcessors * 2); ++i){
- // 创建服务器工作器线程,并将完成端口传递到该线程
- HANDLE ThreadHandle = CreateThread(NULL, 0, ServerWorkThread, completionPort, 0, NULL);
- if(NULL == ThreadHandle){
- cerr << "Create Thread Handle failed. Error:" << GetLastError() << endl;
- system("pause");
- return -1;
- }
- CloseHandle(ThreadHandle);
- }
- // 建立流式套接字
- SOCKET srvSocket = socket(AF_INET, SOCK_STREAM, 0);
- // 绑定SOCKET到本机
- SOCKADDR_IN srvAddr;
- srvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
- srvAddr.sin_family = AF_INET;
- srvAddr.sin_port = htons(DefaultPort);
- int bindResult = bind(srvSocket, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR));
- if(SOCKET_ERROR == bindResult){
- cerr << "Bind failed. Error:" << GetLastError() << endl;
- system("pause");
- return -1;
- }
- // 将SOCKET设置为监听模式
- int listenResult = listen(srvSocket, 10);
- if(SOCKET_ERROR == listenResult){
- cerr << "Listen failed. Error: " << GetLastError() << endl;
- system("pause");
- return -1;
- }
- // 开始处理IO数据
- cout << "本服务器已准备就绪,正在等待客户端的接入...\n";
- // 创建用于发送数据的线程
- HANDLE sendThread = CreateThread(NULL, 0, ServerSendThread, 0, 0, NULL);
- while(true){
- PER_HANDLE_DATA * PerHandleData = NULL;
- SOCKADDR_IN saRemote;
- int RemoteLen;
- SOCKET acceptSocket;
- // 接收连接,并分配完成端,这儿可以用AcceptEx()
- RemoteLen = sizeof(saRemote);
- acceptSocket = accept(srvSocket, (SOCKADDR*)&saRemote, &RemoteLen);
- if(SOCKET_ERROR == acceptSocket){ // 接收客户端失败
- cerr << "Accept Socket Error: " << GetLastError() << endl;
- system("pause");
- return -1;
- }
- // 创建用来和套接字关联的单句柄数据信息结构
- PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA)); // 在堆中为这个PerHandleData申请指定大小的内存
- PerHandleData -> socket = acceptSocket;
- memcpy (&PerHandleData -> ClientAddr, &saRemote, RemoteLen);
- clientGroup.push_back(PerHandleData); // 将单个客户端数据指针放到客户端组中
- // 将接受套接字和完成端口关联
- CreateIoCompletionPort((HANDLE)(PerHandleData -> socket), completionPort, (DWORD)PerHandleData, 0);
- // 开始在接受套接字上处理I/O使用重叠I/O机制
- // 在新建的套接字上投递一个或多个异步
- // WSARecv或WSASend请求,这些I/O请求完成后,工作者线程会为I/O请求提供服务
- // 单I/O操作数据(I/O重叠)
- LPPER_IO_OPERATION_DATA PerIoData = NULL;
- PerIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_OPERATEION_DATA));
- ZeroMemory(&(PerIoData -> overlapped), sizeof(OVERLAPPED));
- PerIoData->databuff.len = 1024;
- PerIoData->databuff.buf = PerIoData->buffer;
- PerIoData->operationType = 0; // read
- DWORD RecvBytes;
- DWORD Flags = 0;
- WSARecv(PerHandleData->socket, &(PerIoData->databuff), 1, &RecvBytes, &Flags, &(PerIoData->overlapped), NULL);
- }
- system("pause");
- return 0;
- }
- // 开始服务工作线程函数
- DWORD WINAPI ServerWorkThread(LPVOID IpParam)
- {
- HANDLE CompletionPort = (HANDLE)IpParam;
- DWORD BytesTransferred;
- LPOVERLAPPED IpOverlapped;
- LPPER_HANDLE_DATA PerHandleData = NULL;
- LPPER_IO_DATA PerIoData = NULL;
- DWORD RecvBytes;
- DWORD Flags = 0;
- BOOL bRet = false;
- while(true){
- bRet = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR)&PerHandleData, (LPOVERLAPPED*)&IpOverlapped, INFINITE);
- if(bRet == 0){
- cerr << "GetQueuedCompletionStatus Error: " << GetLastError() << endl;
- return -1;
- }
- PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(IpOverlapped, PER_IO_DATA, overlapped);
- // 检查在套接字上是否有错误发生
- if(0 == BytesTransferred){
- closesocket(PerHandleData->socket);
- GlobalFree(PerHandleData);
- GlobalFree(PerIoData);
- continue;
- }
- // 开始数据处理,接收来自客户端的数据
- WaitForSingleObject(hMutex,INFINITE);
- cout << "A Client says: " << PerIoData->databuff.buf << endl;
- ReleaseMutex(hMutex);
- // 为下一个重叠调用建立单I/O操作数据
- ZeroMemory(&(PerIoData->overlapped), sizeof(OVERLAPPED)); // 清空内存
- PerIoData->databuff.len = 1024;
- PerIoData->databuff.buf = PerIoData->buffer;
- PerIoData->operationType = 0; // read
- WSARecv(PerHandleData->socket, &(PerIoData->databuff), 1, &RecvBytes, &Flags, &(PerIoData->overlapped), NULL);
- }
- return 0;
- }
- // 发送信息的线程执行函数
- DWORD WINAPI ServerSendThread(LPVOID IpParam)
- {
- while(1){
- char talk[200];
- gets(talk);
- int len;
- for (len = 0; talk[len] != '\0'; ++len){
- // 找出这个字符组的长度
- }
- talk[len] = '\n';
- talk[++len] = '\0';
- printf("I Say:");
- cout << talk;
- WaitForSingleObject(hMutex,INFINITE);
- for(int i = 0; i < clientGroup.size(); ++i){
- send(clientGroup[i]->socket, talk, 200, 0); // 发送信息
- }
- ReleaseMutex(hMutex);
- }
- return 0;
- }
// IOCP_TCPIP_Socket_Server.cpp#include <WinSock2.h>
#include <Windows.h>
#include <vector>
#include <iostream>using namespace std;#pragma comment(lib, "Ws2_32.lib") // Socket编程需用的动态链接库
#pragma comment(lib, "Kernel32.lib") // IOCP需要用到的动态链接库/*** 结构体名称:PER_IO_DATA* 结构体功能:重叠I/O需要用到的结构体,临时记录IO数据**/
const int DataBuffSize = 2 * 1024;
typedef struct
{OVERLAPPED overlapped;WSABUF databuff;char buffer[ DataBuffSize ];int BufferLen;int operationType;
}PER_IO_OPERATEION_DATA, *LPPER_IO_OPERATION_DATA, *LPPER_IO_DATA, PER_IO_DATA;/*** 结构体名称:PER_HANDLE_DATA* 结构体存储:记录单个套接字的数据,包括了套接字的变量及套接字的对应的客户端的地址。* 结构体作用:当服务器连接上客户端时,信息存储到该结构体中,知道客户端的地址以便于回访。**/
typedef struct
{SOCKET socket;SOCKADDR_STORAGE ClientAddr;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;// 定义全局变量
const int DefaultPort = 6000;
vector < PER_HANDLE_DATA* > clientGroup; // 记录客户端的向量组HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
DWORD WINAPI ServerWorkThread(LPVOID CompletionPortID);
DWORD WINAPI ServerSendThread(LPVOID IpParam);// 开始主函数
int main()
{
// 加载socket动态链接库WORD wVersionRequested = MAKEWORD(2, 2); // 请求2.2版本的WinSock库WSADATA wsaData; // 接收Windows Socket的结构信息DWORD err = WSAStartup(wVersionRequested, &wsaData);if (0 != err){ // 检查套接字库是否申请成功cerr << "Request Windows Socket Library Error!\n";system("pause");return -1;}if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){// 检查是否申请了所需版本的套接字库WSACleanup();cerr << "Request Windows Socket Version 2.2 Error!\n";system("pause");return -1;}// 创建IOCP的内核对象/*** 需要用到的函数的原型:* HANDLE WINAPI CreateIoCompletionPort(* __in HANDLE FileHandle, // 已经打开的文件句柄或者空句柄,一般是客户端的句柄* __in HANDLE ExistingCompletionPort, // 已经存在的IOCP句柄* __in ULONG_PTR CompletionKey, // 完成键,包含了指定I/O完成包的指定文件* __in DWORD NumberOfConcurrentThreads // 真正并发同时执行最大线程数,一般推介是CPU核心数*2* );**/HANDLE completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0);if (NULL == completionPort){ // 创建IO内核对象失败cerr << "CreateIoCompletionPort failed. Error:" << GetLastError() << endl;system("pause");return -1;}// 创建IOCP线程--线程里面创建线程池// 确定处理器的核心数量SYSTEM_INFO mySysInfo;GetSystemInfo(&mySysInfo);// 基于处理器的核心数量创建线程for(DWORD i = 0; i < (mySysInfo.dwNumberOfProcessors * 2); ++i){// 创建服务器工作器线程,并将完成端口传递到该线程HANDLE ThreadHandle = CreateThread(NULL, 0, ServerWorkThread, completionPort, 0, NULL);if(NULL == ThreadHandle){cerr << "Create Thread Handle failed. Error:" << GetLastError() << endl;system("pause");return -1;}CloseHandle(ThreadHandle);}// 建立流式套接字SOCKET srvSocket = socket(AF_INET, SOCK_STREAM, 0);// 绑定SOCKET到本机SOCKADDR_IN srvAddr;srvAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);srvAddr.sin_family = AF_INET;srvAddr.sin_port = htons(DefaultPort);int bindResult = bind(srvSocket, (SOCKADDR*)&srvAddr, sizeof(SOCKADDR));if(SOCKET_ERROR == bindResult){cerr << "Bind failed. Error:" << GetLastError() << endl;system("pause");return -1;}// 将SOCKET设置为监听模式int listenResult = listen(srvSocket, 10);if(SOCKET_ERROR == listenResult){cerr << "Listen failed. Error: " << GetLastError() << endl;system("pause");return -1;}// 开始处理IO数据cout << "本服务器已准备就绪,正在等待客户端的接入...\n";// 创建用于发送数据的线程HANDLE sendThread = CreateThread(NULL, 0, ServerSendThread, 0, 0, NULL);while(true){PER_HANDLE_DATA * PerHandleData = NULL;SOCKADDR_IN saRemote;int RemoteLen;SOCKET acceptSocket;// 接收连接,并分配完成端,这儿可以用AcceptEx()RemoteLen = sizeof(saRemote);acceptSocket = accept(srvSocket, (SOCKADDR*)&saRemote, &RemoteLen);if(SOCKET_ERROR == acceptSocket){ // 接收客户端失败cerr << "Accept Socket Error: " << GetLastError() << endl;system("pause");return -1;}// 创建用来和套接字关联的单句柄数据信息结构PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA)); // 在堆中为这个PerHandleData申请指定大小的内存PerHandleData -> socket = acceptSocket;memcpy (&PerHandleData -> ClientAddr, &saRemote, RemoteLen);clientGroup.push_back(PerHandleData); // 将单个客户端数据指针放到客户端组中// 将接受套接字和完成端口关联CreateIoCompletionPort((HANDLE)(PerHandleData -> socket), completionPort, (DWORD)PerHandleData, 0);// 开始在接受套接字上处理I/O使用重叠I/O机制// 在新建的套接字上投递一个或多个异步// WSARecv或WSASend请求,这些I/O请求完成后,工作者线程会为I/O请求提供服务 // 单I/O操作数据(I/O重叠)LPPER_IO_OPERATION_DATA PerIoData = NULL;PerIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_OPERATEION_DATA));ZeroMemory(&(PerIoData -> overlapped), sizeof(OVERLAPPED));PerIoData->databuff.len = 1024;PerIoData->databuff.buf = PerIoData->buffer;PerIoData->operationType = 0; // readDWORD RecvBytes;DWORD Flags = 0;WSARecv(PerHandleData->socket, &(PerIoData->databuff), 1, &RecvBytes, &Flags, &(PerIoData->overlapped), NULL);}system("pause");return 0;
}// 开始服务工作线程函数
DWORD WINAPI ServerWorkThread(LPVOID IpParam)
{HANDLE CompletionPort = (HANDLE)IpParam;DWORD BytesTransferred;LPOVERLAPPED IpOverlapped;LPPER_HANDLE_DATA PerHandleData = NULL;LPPER_IO_DATA PerIoData = NULL;DWORD RecvBytes;DWORD Flags = 0;BOOL bRet = false;while(true){bRet = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR)&PerHandleData, (LPOVERLAPPED*)&IpOverlapped, INFINITE);if(bRet == 0){cerr << "GetQueuedCompletionStatus Error: " << GetLastError() << endl;return -1;}PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(IpOverlapped, PER_IO_DATA, overlapped);// 检查在套接字上是否有错误发生if(0 == BytesTransferred){closesocket(PerHandleData->socket);GlobalFree(PerHandleData);GlobalFree(PerIoData);continue;}// 开始数据处理,接收来自客户端的数据WaitForSingleObject(hMutex,INFINITE);cout << "A Client says: " << PerIoData->databuff.buf << endl;ReleaseMutex(hMutex);// 为下一个重叠调用建立单I/O操作数据ZeroMemory(&(PerIoData->overlapped), sizeof(OVERLAPPED)); // 清空内存PerIoData->databuff.len = 1024;PerIoData->databuff.buf = PerIoData->buffer;PerIoData->operationType = 0; // readWSARecv(PerHandleData->socket, &(PerIoData->databuff), 1, &RecvBytes, &Flags, &(PerIoData->overlapped), NULL);}return 0;
}// 发送信息的线程执行函数
DWORD WINAPI ServerSendThread(LPVOID IpParam)
{while(1){char talk[200];gets(talk);int len;for (len = 0; talk[len] != '\0'; ++len){// 找出这个字符组的长度}talk[len] = '\n';talk[++len] = '\0';printf("I Say:");cout << talk;WaitForSingleObject(hMutex,INFINITE);for(int i = 0; i < clientGroup.size(); ++i){send(clientGroup[i]->socket, talk, 200, 0); // 发送信息}ReleaseMutex(hMutex); }return 0;
}
- // IOCP_TCPIP_Socket_Client.cpp
- #include <iostream>
- #include <cstdio>
- #include <string>
- #include <cstring>
- #include <winsock2.h>
- #include <Windows.h>
- using namespace std;
- #pragma comment(lib, "Ws2_32.lib") // Socket编程需用的动态链接库
- SOCKET sockClient; // 连接成功后的套接字
- HANDLE bufferMutex; // 令其能互斥成功正常通信的信号量句柄
- const int DefaultPort = 6000;
- int main()
- {
- // 加载socket动态链接库(dll)
- WORD wVersionRequested;
- WSADATA wsaData; // 这结构是用于接收Wjndows Socket的结构信息的
- wVersionRequested = MAKEWORD( 2, 2 ); // 请求2.2版本的WinSock库
- int err = WSAStartup( wVersionRequested, &wsaData );
- if ( err != 0 ) { // 返回值为零的时候是表示成功申请WSAStartup
- return -1;
- }
- if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { // 检查版本号是否正确
- WSACleanup( );
- return -1;
- }
- // 创建socket操作,建立流式套接字,返回套接字号sockClient
- sockClient = socket(AF_INET, SOCK_STREAM, 0);
- if(sockClient == INVALID_SOCKET) {
- printf("Error at socket():%ld\n", WSAGetLastError());
- WSACleanup();
- return -1;
- }
- // 将套接字sockClient与远程主机相连
- // int connect( SOCKET s, const struct sockaddr* name, int namelen);
- // 第一个参数:需要进行连接操作的套接字
- // 第二个参数:设定所需要连接的地址信息
- // 第三个参数:地址的长度
- SOCKADDR_IN addrSrv;
- addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 本地回路地址是127.0.0.1;
- addrSrv.sin_family = AF_INET;
- addrSrv.sin_port = htons(DefaultPort);
- while(SOCKET_ERROR == connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))){
- // 如果还没连接上服务器则要求重连
- cout << "服务器连接失败,是否重新连接?(Y/N):";
- char choice;
- while(cin >> choice && (!((choice != 'Y' && choice == 'N') || (choice == 'Y' && choice != 'N')))){
- cout << "输入错误,请重新输入:";
- cin.sync();
- cin.clear();
- }
- if (choice == 'Y'){
- continue;
- }
- else{
- cout << "退出系统中...";
- system("pause");
- return 0;
- }
- }
- cin.sync();
- cout << "本客户端已准备就绪,用户可直接输入文字向服务器反馈信息。\n";
- send(sockClient, "\nAttention: A Client has enter...\n", 200, 0);
- bufferMutex = CreateSemaphore(NULL, 1, 1, NULL);
- DWORD WINAPI SendMessageThread(LPVOID IpParameter);
- DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter);
- HANDLE sendThread = CreateThread(NULL, 0, SendMessageThread, NULL, 0, NULL);
- HANDLE receiveThread = CreateThread(NULL, 0, ReceiveMessageThread, NULL, 0, NULL);
- WaitForSingleObject(sendThread, INFINITE); // 等待线程结束
- closesocket(sockClient);
- CloseHandle(sendThread);
- CloseHandle(receiveThread);
- CloseHandle(bufferMutex);
- WSACleanup(); // 终止对套接字库的使用
- printf("End linking...\n");
- printf("\n");
- system("pause");
- return 0;
- }
- DWORD WINAPI SendMessageThread(LPVOID IpParameter)
- {
- while(1){
- string talk;
- getline(cin, talk);
- WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用)
- if("quit" == talk){
- talk.push_back('\0');
- send(sockClient, talk.c_str(), 200, 0);
- break;
- }
- else{
- talk.append("\n");
- }
- printf("\nI Say:(\"quit\"to exit):");
- cout << talk;
- send(sockClient, talk.c_str(), 200, 0); // 发送信息
- ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕)
- }
- return 0;
- }
- DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter)
- {
- while(1){
- char recvBuf[300];
- recv(sockClient, recvBuf, 200, 0);
- WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用)
- printf("%s Says: %s", "Server", recvBuf); // 接收信息
- ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕)
- }
- return 0;
- }
// IOCP_TCPIP_Socket_Client.cpp#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <winsock2.h>
#include <Windows.h>using namespace std;#pragma comment(lib, "Ws2_32.lib") // Socket编程需用的动态链接库SOCKET sockClient; // 连接成功后的套接字
HANDLE bufferMutex; // 令其能互斥成功正常通信的信号量句柄
const int DefaultPort = 6000;int main()
{
// 加载socket动态链接库(dll)WORD wVersionRequested;WSADATA wsaData; // 这结构是用于接收Wjndows Socket的结构信息的wVersionRequested = MAKEWORD( 2, 2 ); // 请求2.2版本的WinSock库int err = WSAStartup( wVersionRequested, &wsaData );if ( err != 0 ) { // 返回值为零的时候是表示成功申请WSAStartupreturn -1;}if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { // 检查版本号是否正确WSACleanup( );return -1; }// 创建socket操作,建立流式套接字,返回套接字号sockClientsockClient = socket(AF_INET, SOCK_STREAM, 0);if(sockClient == INVALID_SOCKET) { printf("Error at socket():%ld\n", WSAGetLastError()); WSACleanup(); return -1; } // 将套接字sockClient与远程主机相连// int connect( SOCKET s, const struct sockaddr* name, int namelen);// 第一个参数:需要进行连接操作的套接字// 第二个参数:设定所需要连接的地址信息// 第三个参数:地址的长度SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 本地回路地址是127.0.0.1; addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(DefaultPort);while(SOCKET_ERROR == connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))){// 如果还没连接上服务器则要求重连cout << "服务器连接失败,是否重新连接?(Y/N):";char choice;while(cin >> choice && (!((choice != 'Y' && choice == 'N') || (choice == 'Y' && choice != 'N')))){cout << "输入错误,请重新输入:";cin.sync();cin.clear();}if (choice == 'Y'){continue;}else{cout << "退出系统中...";system("pause");return 0;}}cin.sync();cout << "本客户端已准备就绪,用户可直接输入文字向服务器反馈信息。\n";send(sockClient, "\nAttention: A Client has enter...\n", 200, 0);bufferMutex = CreateSemaphore(NULL, 1, 1, NULL); DWORD WINAPI SendMessageThread(LPVOID IpParameter);DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter);HANDLE sendThread = CreateThread(NULL, 0, SendMessageThread, NULL, 0, NULL); HANDLE receiveThread = CreateThread(NULL, 0, ReceiveMessageThread, NULL, 0, NULL); WaitForSingleObject(sendThread, INFINITE); // 等待线程结束closesocket(sockClient);CloseHandle(sendThread);CloseHandle(receiveThread);CloseHandle(bufferMutex);WSACleanup(); // 终止对套接字库的使用printf("End linking...\n");printf("\n");system("pause");return 0;
}DWORD WINAPI SendMessageThread(LPVOID IpParameter)
{while(1){string talk;getline(cin, talk);WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用) if("quit" == talk){talk.push_back('\0');send(sockClient, talk.c_str(), 200, 0);break;}else{talk.append("\n");}printf("\nI Say:(\"quit\"to exit):");cout << talk;send(sockClient, talk.c_str(), 200, 0); // 发送信息ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕) }return 0;
}DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter)
{while(1){ char recvBuf[300];recv(sockClient, recvBuf, 200, 0);WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用) printf("%s Says: %s", "Server", recvBuf); // 接收信息ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕) }return 0;
}
五。本次学习资料
几翻周折,终于写出一个比较简单的IOCP模型的服务器与客户端啦,并且也大概了解这个模型的思路啦~没有买书的娃,伤不起啊,只能从网上搜罗资料,幸好有这些文章在,最后为下列这些文章的作者说声谢谢~
- 顶
- 7
- 踩
- 0
- 4楼 maomzg01333 2012-10-24 20:06发表 [回复] [引用] [举报]
- 我擦 LZ 我太爱你了 我最近对这个特痴狂 哈哈 终于找到 服务器和客户端的了 ,我写了一个IOCP的服务器模型,但是客户端可以连接但是不能发数据,我收藏了,不介意吧,哈哈,最后说句谢谢
- 1楼 OKILOVE 2012-05-30 15:27发表 [回复] [引用] [举报]
- Hi neicole
我试验了一下,从client往server发送信息居然收不到,GetQueuedCompletionStatus没有取消阻塞,你那有这样的情况吗- Re: neicole 2012-05-31 09:15发表 [回复] [引用] [举报]
- 回复OKILOVE:嘿嘿,mark一下,184行的Flags = 0不能漏.
查资料时,网友道:
不是MSG_PEEK,MSG_OOB ,MSG_PARTIAL
所以就取0,这似乎是没什么道理,但winsocket有好多东西在文档里是没有描述的,这是《windows网络编程》里面说的。
lpFlags 是in out型的,所以你不初始化是有问题的。即是传入参数,又是传出参数。
- Re: neicole 2012-05-30 17:07发表 [回复] [引用] [举报]
- 回复OKILOVE:咦~ 我测试的时候没有出现这个情况~ 刚刚再试了一下,还是正常~
- Re: maomzg01333 2012-10-26 17:59发表 [回复] [引用] [举报]
- 回复neicole:恩 确实有这个情况,Send函数在线程里调用是无法发送数据的,我改了一下,把发送函数定义成类成员函数,然后再去调用就可以完成客户端到服务器的发送了,代码如下
class CMySend
{
public:
static void sendBuff()
{
while(1){
string talk;
getline(cin, talk);
send(sockClient, talk.c_str(), 200, 0); // 发送信息
WaitForSingleObject(bufferMutex, INFINITE); // P(资源未被占用)
if("quit" == talk){
talk.push_back('\0');
send(sockClient, talk.c_str(), 200, 0);
break;
}
else{
talk.append("\n");
}
printf("\nI Say:(\"quit\"to exit):");
cout << talk;
ReleaseSemaphore(bufferMutex, 1, NULL); // V(资源占用完毕)
}
}
};
下边是线程函数调用的send函数
CMySend::sendBuff();
静态调用,就可以解决了
一. 建博原因:
1. 记录大学期间学习历程
2. 方便整理归纳回顾知识
3. 受自身历程及众人的监督
4. 认识志同道合的朋友
5. 一起学习交流成长
[博客相关介绍点击这里]
附:我的资料库(点我)
- --> 博客总目录 <--(2)
- 1————————— 分界线(1)
- 【学习_计划_生活】(14)
- 【学习进度记录】每N天的学习小记(19)
- 【Others】其它话题或书籍(8)
- 2————————— 分界线(1)
- 【研究课题及项目】(8)
- 【ACM】刷题记录(2)
- 【Windows编程】(8)
- 【汇编语言】学习记录(15)
- 【C++ 基础类书籍】学习记录(11)
- 【软件设计模式】(1)
- 【算法竞赛入门经典】学习记录(5)
- 【数据库】学习记录(4)
- 【数据结构(C++)】学习记录(22)
- 【C语言】学习记录(1)
- 【Windows网络编程】(6)
- 【编程珠玑】学习记录(1)
- 【QT】学习记录(9)
- 3————————— 分界线(1)
- 〖大学专业相关课程〗复习资料(4)
- 〖10级大一课堂习题〗C++(11)
- 〖10级大二课堂习题〗汇编语言(3)
- 〖10级大二课堂习题〗数据结构(13)
- 〖10级大二课堂习题〗Java(8)
- 〖10级大三课堂〗算法分析(1)
- 4————————— 分界线(1)
- C++其它习题(10)
- C++知识点(6)
- VLC(2)
- Qt相关(2)
- Windows编程(3)
英语,课表满满的课,计算机基础知识思维导图延展。。
近期所感:
生活上,学习上的点点滴滴总是那么的神奇,过去未知答案时所走出的道路,在未来的这天,发觉还真的能将它的点点滴滴串连起来,现在所走之路,未知是何路,但必是通向未来之路~
因为不满足于现状,觉得可以做得更好,所以,常常不断地在寻找着出路,不愿做一只井底之蛙,通过不断努力去改变现状,学习如此,生活亦是如此。不知是何时起,有这么一股想法,这么一股劲,不断寻求,相信总有一天苗子会长大成参天大树。
假如抛开了一切外在负担,你最在乎的是什么?或者说,你最想做的事情是什么? 燃起你的激情,为之奋斗~ 梦&想,梦非仅是梦,想非仅空想,梦想并非遥不可及~ 用这燃烧不尽的激情,追随着它,Achieve it ~ 不要让自己迷失方向,不要让一切邪恶的东西将其覆盖,将其浇灭。
不要冷漠了任何一件事物,它们总是会有这么神奇的一个地方,不断地挖掘挖掘,你会懂得更多,获得更多~ 好奇心是充满魔力的东西~
——2013.03.09 更新
- 我第一年的C++学习之路 —— C++学习方法不断转变(6855)
- (2011.11.12)汇编_王爽_全书_学习小记(3124)
- (2011.11.10) 汇编_王爽_第17章_学习小结(2570)
- 01_南理学工学院OJ_部分简单题目(2360)
- IOCP模型与网络编程(2349)
- (2011.11.07) 汇编_王爽_第15章_学习小结(2335)
- (2011.11.02)汇编_王爽_第10章_学习小结(2123)
- (2011.11.09)汇编_王爽_第16章_学习小结(2054)
- (2011.11.01)汇编_王爽_第09章_学习小结(2037)
- (2011.10.28)汇编_王爽_第六章_学习小结(1911)
- IOCP模型与网络编程
neicole: @sansima05:GlobalAlloc分配内存有两次,主要是在服务器刚刚接收到客户端时,1.保...
- IOCP模型与网络编程
刘沄: 想问一下博主,你的代码里面是否没有考虑释放GlobalAlloc分配的内存?
- 我第一年的C++学习之路 —— C++学习方法不断转变
_難得糊塗: 正在看C++ primer
- (2012.03.08)初次踏上GUI编程之路
neicole: @zhaole20094463::)
- (2012.03.08)初次踏上GUI编程之路
zhaole20094463: 接收,谢谢啦
- (2012.03.08)初次踏上GUI编程之路
neicole: @zhaole20094463:注意接收咯~
- (2012.03.08)初次踏上GUI编程之路
zhaole20094463: 楼主,犀利啊,很少有人可以把学习之路总结的这么清楚的。我也开始学习QT 编程 了,有人什么好的资料,...
- (2013.03.08)求最大公约数_3种算法
neicole: @mazhaojuan:哈哈,还好,近期在学习算法!挺有趣的,不同的角度去解决同一个问题。
- (2013.03.08)求最大公约数_3种算法
马兆娟: 很是深奥偶!
- IOCP模型与网络编程
neicole: @qianluhust:其实运行环境的话,我是在WinXp和Win7做过都没有问题。至于window...
- 我第一年的C++学习之路 —— C++学习方法不断转变(67)
- 2011年的暑假(大一的暑假——还算充实)(20)
- (2012.03.08)初次踏上GUI编程之路(20)
- IOCP模型与网络编程(20)
- (2011.12.14) 杂感:强大的学习动力与我的挚友们。(11)
- (2011.12.01)未有答案:接下来如何写博客呢?(10)
- (2011.09始)大二全学期学习计划(10)
- (2012.01.13)《C程序设计》学习笔记(9)
- 08_简单的命令解析器(小钱版)[操作系统][2012-12-15](9)
- Windows Socket 编程_单个服务器对多个客户端简单通讯(9)
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 多路复用io接口-select()
io多路转接之系统调用 例: select系统调用的多路转接#include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h>int main(int argc, char* argv[]) {fd_set rfds…...
2024/4/21 8:00:09 - OA办公平台、ERP系统、BPM管理软件,哪一个更好用?
企业在部署协同办公系统时,有时候会因为不太清楚各种系统的功能而不知道哪个更好用,OA、ERP、BPM就是其中的例子。 其实软件好不好用,关键还是要看哪个更符合自己的需求,像这三个系统里其实定位各有不同,OA主要管人,BPM主要管业务,ERP主要是对资源管理,虽然三者都涉及到…...
2024/4/21 8:00:09 - HCNA网络技术学习指南-第二章VRP基础
1、VRP简介VRP是Versatile Routing Platform的简称,它是华为公司数据通信产品的通用网络操作系统。VRP以TCP/IP模型为参考。VRP系统将命令和用户进行了分级,每条命令都有相应的级别,每个用户也都有自己的权限级别。 1.1、命令级别与用户权限级别1.2、命令行的使用方法<Hu…...
2024/4/21 8:00:08 - IO复用 select Demo
1 等待键盘输入,输出读入的字节数和读入的内容#include <sys/types.h> #include <sys/time.h> #include <stdio.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #include <stdlib.h>int main() {char buffer[1…...
2024/5/4 17:27:01 - 致远的OA软件有什么特点?
OA的开发语言 OA软件的开发语言很多,目前较为常见的有ASP/PHP/.Lotu Domino/.Net/JAVA 五种语言,五种语言各有特色,其最鲜明的就是——他们代表了“计算机语言发展使用简史”。1. ASP语言ASP是微软的初始WEB产品,在97年左右推向市场,是最初较早的WEB语言技术,很多小型简…...
2024/4/21 8:00:05 - 软件工程——个人总结
团队名字和项目名字_源计划 毕业设计互选系统学习和使用的新软件Dreamweaver CS6 Microsoft SQL Server Management Studio 17 Enterprise Architect学会和使用的新工具莫刀,一款设计原型交互界面的工具。学习和掌握的新语言、新平台ASP VBScript 无新平台统计一下,你在这软件…...
2024/4/21 8:00:05 - Huawei-R&S-网络工程师实验笔记20190525-设备登录、VRP基本配置、文件系统
》Huawei-R&S-网络工程师实验笔记20190525-设备登录、VRP基本配置、文件系统(环回接口、telnet远程、AAA登录、命令行、时钟、banner、文件目录) 》》实验开始,参考《Huawei-R&S-网络工程师实验笔记20190524-XXX》中的拓扑图,使用 Huawei eNSP、Wireshark、Oracle …...
2024/4/20 18:39:21 - winsock之ioctlsocket()
ioctlsocket()简述:控制套接口的模式。#include <winsock.h>int PASCAL FAR ioctlsocket( SOCKET s, long cmd, u_long FAR* argp);s:一个标识套接口的描述字。cmd:对套接口s的操作命令。argp:指向cmd命令所带参数的指针。注释:本函数可用于任一状态的任一套接口。它…...
2024/4/20 18:39:19 - 转 VC线程同步技术剖析
使线程同步 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。 如果不采取适当的措施,其他线程…...
2024/4/20 18:39:18 - OA系统中根据文本框按钮控制执行路径和人员加锁和置灰
//获取任务节点 function afterOnload(){if(document.getElementsByName(lastDestTaskId)!=null &&document.getElementsByName(lastDestTaskId)!=undefined && document.getElementsByName(lastDestTaskId)[0]!=null){var destTask = document.getElementsByN…...
2024/4/20 18:39:17 - 这么swag的荣誉,你们有吗?
为了2018年必须漂亮的收尾,第四季度伊始,小S准备先出个有点swag的小招数。证明我们世平信息(老板要求增加公司名字的曝光度)德智体美全面发展的三项最新荣誉如下:No.1科研实力安全方向研究课题在国家工程实验室主任基金项目中立项由世平信息董事长负责的《面向社会安全数据…...
2024/4/21 8:00:03 - socket网络编程 的基本方法:--ongoing
https://blog.csdn.net/shuxiaogd/article/details/50366039在学习网络编程时,我们总是从最简单的Server程序写起:socket -> bind -> listen -> accept -> read -> write -> return再接下来,就是学习如何处理客户端的并发请求。主要思路有: 使用多线…...
2024/4/21 8:00:03 - OA办公管理系统的功能有什么特点
随着数字化科技的发展,OA办公管理系统是企业不可缺少的办公管理助手。OA办公软件在实际的应用中,包含了企业日常办公所需的功能,尤其是很多企业单位单位最需要的,就是利用OA办公管理软件将业务流程和审批流程打通。甚至是企业的审批流程可以调用业务流程。这将是一个中大型…...
2024/4/21 8:00:01 - 大神的自动练法师技能,想单独提取,练火星球到 75熟练度,,求大神帮忙提取下。
大神的自动练法师技能,想单独提取,练火星球到 75熟练度,,求大神帮忙提取下。 2014-04-26 00:50:02| 分类: assa 脚本范文列 |字号 订阅 下载LOFTER我的照片书 | dim @熟练度,@模式,@标题,@选项,@提示 dim @检测技能,@去练魔法,@去学魔法,@显示,@名字 dim @技能名称,@技能…...
2024/4/21 8:00:01 - 旅行商问题(Traveling Saleman Problem,TSP)
什么是旅行商问题 旅行商问题(Traveling Saleman Problem,TSP)是VRP的特例,由于Gaery[1]已证明TSP问题是NP难题,因此,VRP也属于NP难题。 旅行商问题(TSP)又译为旅行推销员问题、货郎担问题,简称为TSP问题,是最基本的路线问题,该问题是在寻求单一旅行者由起点出发,通过所…...
2024/4/21 7:59:59 - c++的多线程编程
WIN 多线程API一 简单实例比较简单的代码,创建10个线程,其中使第4个线程在一创建就挂起,等到其他的线程执行的差不多的时候再使第4个线程恢复执行。#include <stdio.h> #include <stdlib.h> #include <windows.h> #define THREAD_NUM 10DWORD WINAPI Prin…...
2024/4/21 7:59:59 - 产业企业和投资机会研究 沈阳新松机器人自动化股份有限公司(300024)
产业企业和投资机会研究沈阳新松机器人自动化股份有限公司(300024) 作者:如楠 本文摘要:百度百科简介:沈阳新松机器人自动化股份有限公司是以先进制造技术为核心,真正拥有自主知识产权和核心技术的高新科技企业,是由在科技界享有盛誉的“中国机器人之父”----蒋新松院士的…...
2024/4/21 7:59:57 - 11.HCNA-HNTD——文件系统基础
华为网络设备的配置文件和VRP系统文件都保存在物理存储介质中,所以文件系统是VRP正常运行的基础。只有掌握了对文件系统的基本操作,网络工程师才能对设备的配置文件和VRP系统文件进行高效的管理。学习目标: 掌握文件系统的基本操作 VRP基于文件系统来管理设备上的文件和目录…...
2024/4/21 7:59:58 - VxWorks管道(Pipe)创建与文件操作
VxWorks管道(Pipe)创建与文件操作管道最明显的优势就是支持Select(),这样任务可以同时等待包括管道在内的一系列I/O设备上的数据。此外,PipeDrv提供的几个I/O控制命令也比较有用。使用管道除了需要管道驱动PipeDrv(定义为宏INCLUDE_PIPES)支持外,还需要用到I/O系统库IoLib/I…...
2024/4/21 7:59:56 - 第一节:OA权限管理系统
OYW.OAOA权限管理系统开发工具:Vs2017 (.netcore 2.1)数据库:MSSQLNoSQL:Redisgit开源地址: https://github.com/XXXXX34/OYW.OA运行效果:后续将继续完善.......
2024/4/21 7:59:55
最新文章
- 【Linux 命令操作】如何在 Linux 中使用多行注释呢?
文章目录 1. 给代码进行多行注释2. 给代码取消多行注释 1. 给代码进行多行注释 🐧① 首先用 vim 打开代码,按 Esc进入命令模式(Normal mode); 🐧② 然后按住 ctrl v 进入列模式; 🐧③ 再通过按 h(左)、j(…...
2024/5/8 7:13:00 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/5/7 10:36:02 - PicGo + Gitee + VsCode - 搭建私人图床
文章目录 前言搭建图床VsCode 安装插件安装 PicGo准备 Gitee 图床测试 尾声 前言 本人是一个重度 vimer,并且喜欢客制化一些东西… Typora 固然好用,但不支持 vim…发现 vscode 中既可以使用 vim,也可以 md,用起来比较舒服.因此…...
2024/5/5 10:21:29 - Stable Diffusion的界面参数详解
Stable Diffusion作为一款强大的文本到图像生成模型,其界面参数是用户与模型进行交互的重要桥梁。这些参数不仅影响着模型的生成效果,还能够帮助用户更加精准地控制生成图像的风格、内容等。本文将详细介绍Stable Diffusion的界面参数,帮助用户更好地理解和应用这一工具。 …...
2024/5/5 23:17:17 - Node.js------Express
◆ 能够使用 express.static( ) 快 速 托 管 静 态 资 源◆ 能够使用 express 路 由 精 简 项 目 结 构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念ÿ…...
2024/5/7 15:39:19 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/8 6:01:22 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/7 9:45:25 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/5/4 23:54:56 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/7 14:25:14 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/5/4 23:54:56 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/5/4 23:55:05 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/5/4 23:54:56 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/5/7 11:36:39 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/5/4 23:54:56 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/6 1:40:42 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/5/4 23:54:56 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/5/4 23:55:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/5/7 9:26:26 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/5/4 23:54:56 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/4 23:55:06 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/5 8:13:33 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/5/4 23:55:16 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/5/4 23:54:58 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/6 21:42:42 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/5/4 23:54:56 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57