MFC_IO模型CreateIoCompletionPort完成端口
先上代码,以后写注释
// select服务端Dlg.cpp : 实现文件 // #include "stdafx.h" #include "select服务端.h" #include "select服务端Dlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif #define WM_SOCKET WM_USER + 1 struct CompletionPortAndMyHwnd {//目的是在工作线程中得到窗口指针 HANDLE CompletionPort; Cselect服务端Dlg* my_win; }compleportandHwnd; // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // Cselect服务端Dlg 对话框 Cselect服务端Dlg::Cselect服务端Dlg(CWnd* pParent /*=NULL*/) : CDialog(Cselect服务端Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void Cselect服务端Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(Cselect服务端Dlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON1, &Cselect服务端Dlg::OnBnClickedButton1) ON_WM_DESTROY() END_MESSAGE_MAP() // Cselect服务端Dlg 消息处理程序 BOOL Cselect服务端Dlg::OnInitDialog() { CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 this->SetDlgItemText(IDC_EDIT5,_T("127.0.0.1")); this->SetDlgItemText(IDC_EDIT2,_T("8009")); char abc[]="我是abc"; int a = sizeof(abc); int b = strlen(abc); count1 = 0; evetnHandle = CreateEvent(NULL,TRUE,TRUE,NULL); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void Cselect服务端Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void Cselect服务端Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR Cselect服务端Dlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } BOOL Cselect服务端Dlg::InItSocket()//装载套接字库 { WSADATA data = {0}; if(WSAStartup(MAKEWORD(2, 2), &data))//2.2的套接字 return FALSE; if ( LOBYTE(data.wVersion) !=2 || HIBYTE(data.wVersion) != 2 ){ WSACleanup(); return FALSE; } return TRUE; } PER_IO_OPERATION_DATA * Cselect服务端Dlg::getPerBy_SOCKET(SOCKET s){ //遍历结构集合 /*for(int i=0;i<perList.GetSize();i++){ int aa = perList.GetAt(i)->socket; if(perList.GetAt(i)->socket == s){ return perList.GetAt(i); } }*/ return NULL; } DWORD WINAPI WorkerThread(LPVOID CompletionPortID)//工作者线程 { HANDLE CompletionPort=(HANDLE)compleportandHwnd.CompletionPort;//取出完成端口句柄 Cselect服务端Dlg* pDlg=compleportandHwnd.my_win;//取出窗口指针 SOCKET sClient; DWORD dwBytesTransferred;//重叠结构中的字节数 PER_IO_OPERATION_DATA* lpPerIOData1 = NULL; while (TRUE) { //取完成端口状态 GetQueuedCompletionStatus( CompletionPort,//完成端口句柄 &dwBytesTransferred,//接受数据的大小 (unsigned long *)&sClient,//客户端,也就是我们创建完成端口的时候传入的那个自定义数据 (LPOVERLAPPED *)&lpPerIOData1,//这个就是recive的时候的那个缓冲区了 INFINITE);//无限等待 int i=0; if (dwBytesTransferred == 0xFFFFFFFF)//如果是退出的信号,由PostQueuedCompletionStatus发出的 { return TRUE;//返回 } if (lpPerIOData1->OperationType == RECV_POSTED)//重叠结构中的枚举值 { if (dwBytesTransferred == 0) { //客户端关闭 //循环动态数组删除结构体元素 for(int i=0;i<pDlg->perList.GetSize();i++){ int aa = pDlg->perList.GetAt(i)->socket; if(pDlg->perList.GetAt(i)->socket == sClient){ pDlg->perList.RemoveAt(i); break; } } //Cilentinfo c = *(pDlg->m_Cilentinfo.GetAt(i)); //if (sClient==c.cinsock) //{ // break; //} //continue; CString cip; //cip.Format(_T("客户%s离开"),pDlg->m_Cilentinfo.GetAt(i).cinIP); // pDlg->m_Cilentinfo.RemoveAt(i);//从动态数组中删除这个 节点 // pDlg->SetDlgItemText(IDC_EDIT1,cip); closesocket(sClient);//关闭客户端套接字 delete lpPerIOData1; //HeapFree(GetProcessHeap(),0,lpPerIOData1); //释放这前申请的内存 } else { //********************************************************************** //处理客户端请求,可以起个线程什么的用于传文件之类的 lpPerIOData1->szMessage[dwBytesTransferred] = '\0';//客户端发过来的信息 //for (i=0;i<pDlg->m_Cilentinfo.GetSize();i++)//以套接字为标,找出动态数组相应IP //{ // if (sClient==pDlg->m_Cilentinfo.GetAt(i).cinsock) // { // break; // } //} CString sMsg; USES_CONVERSION; char* tempbuff = (char*)A2W(lpPerIOData1->szMessage); sMsg.Format(_T("%s"),tempbuff); AfxMessageBox(sMsg); // pDlg->SetDlgItemText(IDC_EDIT1,sMsg); // for (i=0;i<pDlg->m_Cilentinfo.GetSize();i++)//回传给所有动态数组中的客户 { // send(pDlg->m_Cilentinfo.GetAt(i).cinsock, sMsg, strlen(sMsg), 0); } //********************************************************************** //重新激活另一个WSARecv异步操作 memset(lpPerIOData1, 0, sizeof(PER_IO_OPERATION_DATA)); //lpPerIOData1 = pDlg->getPerBy_SOCKET(s);//重新发送一次请求 //删除临时变量 lpPerIOData1->Buffer.len = 1024; lpPerIOData1->Buffer.buf = lpPerIOData1->szMessage; lpPerIOData1->OperationType = RECV_POSTED; lpPerIOData1->socket = sClient; WSARecv(sClient, &lpPerIOData1->Buffer, 1, &lpPerIOData1->NumberOfBytesRecvd, &lpPerIOData1->Flags, &lpPerIOData1->overlap, NULL); } }} return NULL; } DWORD WINAPI ThreadFunc(LPVOID pParam){ Cselect服务端Dlg* pDlg=(Cselect服务端Dlg *)pParam;//取出传过来的窗口指针 DWORD dwThreadId; SYSTEM_INFO systeminfo;//系数信息,主要是用于取得CPU数量 PER_IO_OPERATION_DATA* lpPerIOData;//扩展重叠结构,为每创建一个socket分配一个这样的一个扩展结构,他的作用是用于获得用户发送的数据,也就是缓冲区 //创建一个完成端口,这里只是为了得到它的句柄,后面再和套接字关联起来 compleportandHwnd.CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);//创建一个完成端口,然后交给多线程 compleportandHwnd.my_win=pDlg; //创建工作者线程 GetSystemInfo(&systeminfo); for (unsigned int i=0;i<systeminfo.dwNumberOfProcessors;i++)//以CPU的数量来创建 { CreateThread(NULL, 0, WorkerThread, &compleportandHwnd, 0, &dwThreadId); //把完成端口句柄传过去附带了窗口指针 } //装载socket库 if (pDlg->InItSocket()) { // AfxMessageBox("装载套接字库出错!"); } // pDlg->sSever=socket(AF_INET , SOCK_STREAM , IPPROTO_TCP); //创建套接字,服务端监听的套接字 if (INVALID_SOCKET==pDlg->sSever) { //AfxMessageBox(_T("创建套接字失败!")); } // sockaddr_in serve; CString ip; pDlg->GetDlgItemText(IDC_EDIT5,ip); USES_CONVERSION; serve.sin_addr.S_un.S_addr = inet_addr(W2A(ip.GetBuffer())); ip.ReleaseBuffer(); serve.sin_family = AF_INET; pDlg->GetDlgItemText(IDC_EDIT2,ip); serve.sin_port = htons(_tstoi(ip.GetBuffer())); ip.ReleaseBuffer(); bind(pDlg->sSever, (struct sockaddr *)&serve, sizeof(SOCKADDR_IN)); // if (SOCKET_ERROR==listen(pDlg->sSever,5)) { AfxMessageBox(_T("监听失败!")); } //*************************** //pDlg->SetDlgItemText(IDC_EDIT1,"服务端开启成功!"); SOCKADDR_IN sCilentaddr; int len=sizeof(struct sockaddr); //接受连接 //DWORD ret = WaitForSingleObject(pDlg->evetnHandle,0); //CString cilentIPstr=A2W(inet_ntoa(sCilentaddr.sin_addr));//连接IP //CString cstr; CString count111; AfxMessageBox(_T("服务端开启成功!")); while (TRUE) { pDlg->sClient = accept(pDlg->sSever, (struct sockaddr *)&sCilentaddr, &len); pDlg->count1++; count111.Format(_T("连接数量是:%d"),pDlg->count1); //SetEvent(pDlg->evetnHandle); pDlg->SetDlgItemText(IDC_EDIT3,count111); // cstr.Format("IP:%s连上来了!",cilentIPstr); //保存到动态数组 //Cilentinfo* clientinfo = new Cilentinfo();//每一个客户端保存一个socket,保存到数组里面, 也可以放在缓存那个结构里面,所以这里直接注释 //clientinfo->cinsock=sClient;//套接字 //clientinfo->cinIP= cilentIPstr; //m_Cilentinfo.Add(clientinfo); //加入动态数组中 //新接受的连接套接字关联到完成端口 CreateIoCompletionPort((HANDLE)(pDlg->sClient),compleportandHwnd.CompletionPort, pDlg->sClient, 0); //客户端, 完成端口句柄 传递一个参数给完成端口,在GetQueuedCompletionStatus 获取的时候会需要,后面个一般为0 //激活一个WSARecv异步操作 //lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc( // GetProcessHeap(), // HEAP_ZERO_MEMORY, // sizeof(PER_IO_OPERATION_DATA));//重叠结构申请内存 lpPerIOData = new PER_IO_OPERATION_DATA();//分配堆上的内存 lpPerIOData->Buffer.len = 1024;//大小 lpPerIOData->OperationType = RECV_POSTED;//类型 lpPerIOData->Buffer.buf = lpPerIOData->szMessage;//缓冲区 lpPerIOData->socket = pDlg->sClient;//分配一个socket //把结构体加入到 array pDlg->perList.Add(lpPerIOData); //意思是给重叠的队列发送一个消息 WSARecv(pDlg->sClient,//需要监听的socket &(lpPerIOData->Buffer),//缓冲区,也就是服务器发送过来的数据 1,//只有一个缓冲区 &(lpPerIOData->NumberOfBytesRecvd),//接受的大小,这个send的时候才会有用,所以这个乱填 &(lpPerIOData->Flags),//标致,好像必须为0 &(lpPerIOData->overlap),//重叠机构 NULL); } //向完成端口中的线程发出退出信号 PostQueuedCompletionStatus(compleportandHwnd.CompletionPort, 0xFFFFFFFF, 0, NULL); return NULL; } void Cselect服务端Dlg::OnBnClickedButton1() { HANDLE m_hConnectThread=CreateThread(NULL,0,ThreadFunc,this,0,NULL); } void Cselect服务端Dlg::OnDestroy() { //销毁资源,关闭socket //for(int i=0;i<perList.GetSize();i++){ // delete perList.GetAt(i); // } closesocket(sSever); CloseHandle(compleportandHwnd.CompletionPort);//关闭完成端口 WSACleanup();//拆卸套接字 CDialog::OnDestroy(); }
typedef enum//枚举 状态 { RECV_POSTED }OPERATION_TYPE; struct Cilentinfo { SOCKET cinsock; CString cinIP; }cilentin; typedef struct//扩展重叠结构 { WSAOVERLAPPED overlap; SOCKET socket; WSABUF Buffer; char szMessage[1024]; DWORD NumberOfBytesRecvd; DWORD Flags; OPERATION_TYPE OperationType; }PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;
// select服务端Dlg.h : 头文件 // #pragma once #include <winsock.h> #pragma comment(lib, "ws2_32.lib") #include "MyData.h" // Cselect服务端Dlg 对话框 class Cselect服务端Dlg : public CDialog { // 构造 public: Cselect服务端Dlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_SELECT_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedButton1(); SOCKET sSever,sClient; //套接字 CArray <Cilentinfo*,Cilentinfo*&>m_Cilentinfo;//动态数组客户套接字及IP //CArray <PER_IO_OPERATION_DATA*,PER_IO_OPERATION_DATA*&> perList;//结构和套接字绑定的一个结构 CList <PER_IO_OPERATION_DATA*,PER_IO_OPERATION_DATA*&> perList;//结构和套接字绑定的一个结构 BOOL InItSocket(); PER_IO_OPERATION_DATA * getPerBy_SOCKET(SOCKET s); int count1; HANDLE evetnHandle; protected: // virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); public: afx_msg void OnDestroy(); };

浙公网安备 33010602011771号