2006年02月25日
2005年06月23日

/*
 WinSock I/O Module
  —Select IO Module
 Server Example 1.0  
 
 Author: yaliao [lya_118@163.com]
*/

#include <winsock2.h>
#include <mswsock.h>
#include <iostream.h>
#include <conio.h>

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

#define    BUFFER_SIZE           4096
#define    MAX_THREADS            9
SOCKET Listen;
HANDLE ThreadPool[MAX_THREADS];
static int nThreadCout = 0;
volatile long dwClients = 0;
DWORD  WINAPI  WorkerThread(LPVOID  lpParam);
CRITICAL_SECTION csAccept;
bool DoAccept(SOCKET &c);
bool IsRead(SOCKET &c);
bool IsWrite(SOCKET &c);
bool bContinue = true;
char sndBuf[] = "\t Welcome to Select IO Module server\r\n";;

void main()
{
 WSADATA wsaData;

 int nRet, i;
 
 nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
 if(nRet != 0)
 {
  cout <<"WSAStartup Failed: " <<WSAGetLastError() <<endl;
  return;
 }

 Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
    if (INVALID_SOCKET == Listen)
    {
  cout <<"socket Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        return;
    }
   
    SOCKADDR_IN inAddr;
   
    inAddr.sin_family = AF_INET;
 inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 inAddr.sin_port = htons(5150);  

    nRet = bind(Listen, (PSOCKADDR)&inAddr, sizeof(inAddr));

    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"bind Failed: " <<WSAGetLastError() <<endl;
  WSACleanup();
        return;
    } 
 
 nRet = listen(Listen, 20);
 
    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"listen Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        return;
    } 
 ZeroMemory(ThreadPool, MAX_THREADS);
 InitializeCriticalSection(&csAccept);
 HANDLE hThread;
 for(i=0; i<MAX_THREADS; i++)
 {
  hThread = CreateThread(NULL, 0, WorkerThread, NULL, CREATE_SUSPENDED, NULL);
  if(NULL != hThread)
  {
   ThreadPool[nThreadCout] = hThread;
   nThreadCout++;
     }
 }
 
 if(nThreadCout < MAX_THREADS)
 {
  closesocket(Listen);
  cout <<"CreateThread Failed: " <<GetLastError() <<endl;
        WSACleanup();
        for(i=0; i<nThreadCout; i++)
         CloseHandle(ThreadPool[i]);
        return;
 }
 
 for(i=0; i<MAX_THREADS; i++)
 {
  ResumeThread(ThreadPool[i]);
  CloseHandle(ThreadPool[i]);
 }

    cout <<"Enter ‘q’ to exit: " <<endl;
    while(getch() != ‘q’);
 cout <<"Main thread will exit " <<endl;
 closesocket(Listen);
 WSACleanup();
 bContinue = false;
 DeleteCriticalSection(&csAccept);
 getch();
}

DWORD  WINAPI  WorkerThread(LPVOID  lpParam) 

 SOCKET client;
 char rcvBuf[BUFFER_SIZE];
 int nRet;
 
 cout <<"WorkerThread…" <<endl;
 while(bContinue)
 {
  if(DoAccept(client))
  {
   if(IsWrite(client))
   {
    nRet = send(client, sndBuf, strlen(sndBuf), 0);
    if (SOCKET_ERROR == nRet)
    {
     closesocket(client);
     InterlockedDecrement(&dwClients);
     cout<<" send error…" <<endl;
     cout<<" client disconnected…" <<endl;
     continue;
    }
    if(0 == nRet)
    {
     closesocket(client);
     InterlockedDecrement(&dwClients);
     cout<<" client disconnected…" <<endl;
     continue;
    }
    cout <<"Send: " <<sndBuf <<endl; 
   }
   while(true)
   {
    if(IsRead(client))
    {
     cout <<" Read Data…" <<endl;
     ZeroMemory(rcvBuf, BUFFER_SIZE);
     nRet = recv(client, rcvBuf, BUFFER_SIZE, 0);
     if (SOCKET_ERROR == nRet)
     {
      closesocket(client);
      InterlockedDecrement(&dwClients);
      cout<<" recv error…" <<endl;
      cout<<" client disconnected… total = " <<dwClients <<endl;
      break;
     }
     if(0 == nRet)
     {
      closesocket(client);
      InterlockedDecrement(&dwClients);
      cout<<" client disconnected… total = " <<dwClients <<endl;
      break;
     }
     cout <<" Recv: " <<rcvBuf <<endl;

     if(IsWrite(client))
     {
      nRet = send(client, rcvBuf, strlen(rcvBuf), 0);
      if (SOCKET_ERROR == nRet)
      {
       closesocket(client);
       InterlockedDecrement(&dwClients);
       cout<<" send error…" <<endl;
       cout<<" client disconnected… total = " <<dwClients <<endl;
       break;
      }
      if(0 == nRet)
      {
       closesocket(client);
       InterlockedDecrement(&dwClients);
       cout<<" client disconnected… total = " <<dwClients <<endl;
       break;
      }
      cout <<" Send: " <<rcvBuf <<endl; 
     }
    }
   }
  }
 }
 return 0;

bool DoAccept(SOCKET &c)
{
 int nRet;
 //cout <<"DoAccept accept…" <<endl;
 EnterCriticalSection(&csAccept);
 fd_set FDSet ;
    struct timeval timeout;
    timeout.tv_sec = 3;
    timeout.tv_usec = 0;

    FD_ZERO(&FDSet);
    FD_SET(Listen, &FDSet);
    nRet = select(0, &FDSet, NULL,NULL, &timeout);
   
    if(nRet < 0)
    {
     cout <<"DoAccept select error…" <<endl;
     LeaveCriticalSection(&csAccept);
     return false;
    }
    if(nRet == 0)
    {
     //cout <<"DoAccept select timeout…" <<endl;
     LeaveCriticalSection(&csAccept);
     return false;
    }
    c = accept(Listen, NULL, NULL);
 LeaveCriticalSection(&csAccept);
 if(c == INVALID_SOCKET)
 {
  cout <<"DoAccept accept error…" <<endl;
  return false;
 }
 //为了对客户端连接数进行检查,必须使连接数小于工作线程数,最好
 //的办法为比工作线程数少一个,每次有且只有一个工作线程负责检查
 //如果客户端连接数和工作线程数相同,那么所有工作线程都已进入了
 //读取客户端数据的循环中,无法运行到接受连接的过程中,这样就无
 //法对客户端连接数进行检查,即使客户端退出了运行到接受连接的过
 //程,但此时客户端已经减了一个,检查肯定会小于工作线程数。
 //这个代码的目的是防止客户端连上来,但得不到服务端任何回应,除非
 //处于工作线程中的某个客户端退出,但此时为时已晚了,而且还会造成
 //网络堵塞,大量数据等待接收处理。
 if(dwClients >= nThreadCout-1)
 {
  closesocket(c);
  cout <<"DoAccept too many connected…" <<endl;
  return false;
 }
 InterlockedIncrement(&dwClients);
 cout <<"client connected… total = " <<dwClients <<endl;
 return true;
}

bool IsRead(SOCKET &c)
{
 int nRet;
 fd_set FDSet;
    struct timeval timeout;

    timeout.tv_sec = 1;
    timeout.tv_usec = 100000;
    FD_ZERO(&FDSet);
    FD_SET(c, &FDSet);

    nRet = select(0, &FDSet, NULL,NULL, &timeout);
   
    if(nRet < 0)
    {
     cout <<"IsRead select error…" <<endl;
     return false;
    }
    if(nRet == 0)
    {
     //cout <<"IsRead select timeout…" <<endl;
     return false;
    }

    if(FD_ISSET(c, &FDSet))
 {
  cout <<"IsRead…" <<endl;
  return true;
 }
 cout <<"IsRead FD_ISSET failed…" <<endl;
 return false;
}

bool IsWrite(SOCKET &c)
{
 int nRet;
 fd_set FDSet;
    struct timeval timeout;

    timeout.tv_sec = 1;
    timeout.tv_usec = 100000;
    FD_ZERO(&FDSet);
    FD_SET(c, &FDSet);

    nRet = select(0, NULL, &FDSet,NULL, &timeout);
   
    if(nRet < 0)
    {
     cout <<"IsWrite select error…" <<endl;
     return false;
    }
    if(nRet == 0)
    {
     //cout <<"IsWrite select timeout…" <<endl;
     return false;
    }

    if(FD_ISSET(c, &FDSet))
 {
  cout <<"IsWrite…" <<endl;
  return true;
 }
 cout <<"IsWrite FD_ISSET failed…" <<endl;
 return false;
}

// WsaAsyncSelectDlg.h : header file
//

#if !defined(AFX_WSAASYNCSELECTDLG_H__A5C32F51_4422_4F82_A512_E2269F531551__INCLUDED_)
#define AFX_WSAASYNCSELECTDLG_H__A5C32F51_4422_4F82_A512_E2269F531551__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <winsock2.h>

#define WM_SOCKET  WM_USER+100
/////////////////////////////////////////////////////////////////////////////
// CWsaAsyncSelectDlg dialog

class CWsaAsyncSelectDlg : public CDialog
{
// Construction
public:
 CWsaAsyncSelectDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
 //{{AFX_DATA(CWsaAsyncSelectDlg)
 enum { IDD = IDD_WSAASYNCSELECT_DIALOG };
 CButton m_exit;
 CButton m_stop;
 CButton m_start;
 CListCtrl m_ctrl;
 //}}AFX_DATA

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CWsaAsyncSelectDlg)
 public:
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 protected:
 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
 //}}AFX_VIRTUAL
 private:
  SOCKET  Listen;
  void AddMsg(CString sMsg);
// Implementation
protected:
 HICON m_hIcon;

 // Generated message map functions
 //{{AFX_MSG(CWsaAsyncSelectDlg)
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 afx_msg void OnStartListen();
 afx_msg void OnStopListen();
 afx_msg void OnExit();
 afx_msg LRESULT OnSocket(WPARAM wParam, LPARAM lParam);
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_WSAASYNCSELECTDLG_H__A5C32F51_4422_4F82_A512_E2269F531551__INCLUDED_)
=================================================================================

// WsaAsyncSelectDlg.cpp : implementation file
//

#include "stdafx.h"
#include "WsaAsyncSelect.h"
#include "WsaAsyncSelectDlg.h"

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

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MAX_LINES 1024
static long nCout = 0;
#define BUFFER_SIZE 4096
char szHello[] = "\t Welcome to WsaAsyncSelect IO Module Server\r\n";
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
 CAboutDlg();

// Dialog Data
 //{{AFX_DATA(CAboutDlg)
 enum { IDD = IDD_ABOUTBOX };
 //}}AFX_DATA

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CAboutDlg)
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL

// Implementation
protected:
 //{{AFX_MSG(CAboutDlg)
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
 //{{AFX_DATA_INIT(CAboutDlg)
 //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAboutDlg)
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 //{{AFX_MSG_MAP(CAboutDlg)
  // No message handlers
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWsaAsyncSelectDlg dialog

CWsaAsyncSelectDlg::CWsaAsyncSelectDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CWsaAsyncSelectDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CWsaAsyncSelectDlg)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CWsaAsyncSelectDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CWsaAsyncSelectDlg)
 DDX_Control(pDX, IDC_EXIT, m_exit);
 DDX_Control(pDX, IDC_STOP, m_stop);
 DDX_Control(pDX, IDC_START, m_start);
 DDX_Control(pDX, IDC_LIST1, m_ctrl);
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CWsaAsyncSelectDlg, CDialog)
 //{{AFX_MSG_MAP(CWsaAsyncSelectDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_START, OnStartListen)
 ON_BN_CLICKED(IDC_STOP, OnStopListen)
 ON_BN_CLICKED(IDC_EXIT, OnExit)
 ON_MESSAGE(WM_SOCKET, OnSocket)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWsaAsyncSelectDlg message handlers

BOOL CWsaAsyncSelectDlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Add "About…" menu item to system menu.

 // IDM_ABOUTBOX must be in the system command range.
 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);
  }
 }

 // Set the icon for this dialog.  The framework does this automatically
 //  when the application’s main window is not a dialog
 SetIcon(m_hIcon, TRUE);   // Set big icon
 SetIcon(m_hIcon, FALSE);  // Set small icon
 
 // TODO: Add extra initialization here
 m_ctrl.InsertColumn(0,_T("时间"),LVCFMT_LEFT,72,-1);
 m_ctrl.InsertColumn(1,_T("信息"),LVCFMT_LEFT,512,-1);
 m_ctrl.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
 m_ctrl.SetTextColor(RGB(0,0,255));

 return TRUE;  // return TRUE  unless you set the focus to a control
}

void CWsaAsyncSelectDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
 }
 else
 {
  if(SC_CLOSE == nID)
  {
   closesocket(Listen);
   WSACleanup(); 
  }
  CDialog::OnSysCommand(nID, lParam);
 }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CWsaAsyncSelectDlg::OnPaint()
{
 if (IsIconic())
 {
  CPaintDC dc(this); // device context for painting

  SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

  // Center icon in client rectangle
  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;

  // Draw the icon
  dc.DrawIcon(x, y, m_hIcon);
 }
 else
 {
  CDialog::OnPaint();
 }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CWsaAsyncSelectDlg::OnQueryDragIcon()
{
 return (HCURSOR) m_hIcon;
}

void CWsaAsyncSelectDlg::AddMsg(CString sMsg)
{
 if(nCout > MAX_LINES)
 {
  m_ctrl.DeleteAllItems();
  nCout = 0;
 }
 m_ctrl.InsertItem(nCout, CTime::GetCurrentTime().Format("%H:%M:%S"));
 m_ctrl.SetItemText(nCout, 1, sMsg);
 m_ctrl.SetHotItem(nCout);
 m_ctrl.EnsureVisible(nCout, FALSE);
 nCout++;
}

void CWsaAsyncSelectDlg::OnStartListen()
{
 // TODO: Add your control notification handler code here
 WSADATA wsaData;
 int nRet;
 CString sMsg;
 sMsg.Empty();
 nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
 if(nRet != 0)
 {
  sMsg.Format("WSAStartup Failed: %d",WSAGetLastError());
  AddMsg(sMsg);
  WSACleanup();
  return;
 }
 
 Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

 if (INVALID_SOCKET == Listen)
 {
  sMsg.Format("socket Failed: %d",WSAGetLastError());
  AddMsg(sMsg);
  WSACleanup();
  return;
 }

 SOCKADDR_IN inAddr;

 inAddr.sin_family = AF_INET;
 inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 inAddr.sin_port = htons(5150);  

 nRet = bind(Listen, (PSOCKADDR)&inAddr, sizeof(inAddr));

 if (SOCKET_ERROR == nRet)
 {
  closesocket(Listen);
  sMsg.Format("bind Failed: %d",WSAGetLastError());
  AddMsg(sMsg);
  WSACleanup();
  return;
 } 
 
 nRet = WSAAsyncSelect(Listen, this->m_hWnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE);
 if (SOCKET_ERROR == nRet)
 {
  closesocket(Listen);
  sMsg.Format("WSAAsyncSelect Failed: %d",WSAGetLastError());
  AddMsg(sMsg);
  WSACleanup();
  return;
 }  

 nRet = listen(Listen, 20);

 if (SOCKET_ERROR == nRet)
 {
  closesocket(Listen);
  sMsg.Format("listen Failed: %d",WSAGetLastError());
  AddMsg(sMsg);
  WSACleanup();
  return;
 }
 m_start.EnableWindow(FALSE);
 m_stop.EnableWindow(TRUE);
}

void CWsaAsyncSelectDlg::OnStopListen()
{
 // TODO: Add your control notification handler code here
 closesocket(Listen);
 WSACleanup();
 CString sMsg;
 sMsg.Empty();
 sMsg.Format("stop listen succeed.");
 AddMsg(sMsg);
 m_start.EnableWindow(TRUE);
 m_stop.EnableWindow(FALSE);
}

void CWsaAsyncSelectDlg::OnExit()
{
 // TODO: Add your control notification handler code here
 PostMessage(WM_SYSCOMMAND,SC_CLOSE);
}

LRESULT CWsaAsyncSelectDlg::OnSocket(WPARAM wParam, LPARAM lParam)
{
 CString sMsg;
 SOCKET client;
 char recvBuf[BUFFER_SIZE];
 sMsg.Empty();
 int nRet;

 if(WSAGETSELECTERROR(lParam))
 {
  closesocket(wParam);
  sMsg.Format("Client disconnected socket: %d",wParam);
 }
 else
 {
  switch(WSAGETSELECTEVENT(lParam))
  {
   case FD_ACCEPT:
    client = accept(wParam, NULL, NULL);
    if(client == INVALID_SOCKET)
    {
     sMsg.Format("accept failed: Socket= %d Error = %d",wParam, WSAGetLastError());
     OnStopListen();
           break;
    }
    nRet = WSAAsyncSelect(client, this->m_hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
    if (SOCKET_ERROR == nRet)
    {
     closesocket(client);
     sMsg.Format("WSAAsyncSelect failed: Socket= %d Error = %d",client, WSAGetLastError());
     break;
    }
    sMsg.Format("Client connected: Socket= %d",client);
    break;
   case FD_READ:
    ZeroMemory(recvBuf, BUFFER_SIZE);
    nRet = recv(wParam, recvBuf, BUFFER_SIZE, 0);
    if (SOCKET_ERROR == nRet)
    {
     closesocket(wParam);
     sMsg.Format("recv failed: Socket= %d Error = %d",wParam, WSAGetLastError());
     break;
    }
    sMsg.Format("recv succeed: recvBuf= %s",recvBuf);
    break;
   case FD_WRITE:
    nRet = send(wParam, szHello, strlen(szHello), 0);
    if (SOCKET_ERROR == nRet)
    {
     closesocket(wParam);
     sMsg.Format("send failed: Socket= %d Error = %d",wParam, WSAGetLastError());
     break;
    }
    sMsg.Format("send succeed: sendBuf= %s",szHello);
    break;
   case FD_CLOSE:
    closesocket(wParam);
    sMsg.Format("Client disconnected socket: %d",wParam);
    break;
   default:
    break;
  }
 }
 AddMsg(sMsg);
 return 0;
}

BOOL CWsaAsyncSelectDlg::PreTranslateMessage(MSG* pMsg)
{
 // TODO: Add your specialized code here and/or call the base class
 if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN) //屏蔽ENTER键
  return TRUE;
 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE)//屏蔽ESC键
  return TRUE;
 return CDialog::PreTranslateMessage(pMsg);
}

2005年06月13日

/*
 WinSock I/O Module
  —WSAEventSelect IO Module
 Server Example 1.0  
 
 Author: yaliao [lya_118@163.com]
*/

#include <winsock2.h>
#include <mswsock.h>
#include <iostream.h>
#include <conio.h>

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

#define    BUFFER_SIZE           4096

SOCKET Sockets[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT Events[WSA_MAXIMUM_WAIT_EVENTS];
char recvBuffer[BUFFER_SIZE];
char sendBuffer[] = "\t Welcome to WSAEventSelect IO Module server\r\n";
DWORD dwTotal = 0;
volatile long dwClients = 0;

DWORD GetInvalidIndex();
DWORD WINAPI ThreadEvent(LPVOID lpParam);
SOCKET Listen;

void main()
{
 WSADATA wsaData;

 int nRet;
 
 nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
 if(nRet != 0)
 {
  cout <<"WSAStartup Failed: " <<WSAGetLastError() <<endl;
  return;
 }

 Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
    if (INVALID_SOCKET == Listen)
    {
  cout <<"socket Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        return;
    }
   
    SOCKADDR_IN inAddr;
   
    inAddr.sin_family = AF_INET;
 inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 inAddr.sin_port = htons(5150);  

    nRet = bind(Listen, (PSOCKADDR)&inAddr, sizeof(inAddr));

    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"bind Failed: " <<WSAGetLastError() <<endl;
  WSACleanup();
        return;
    } 
   
 for(int i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++)
 {
  Sockets[i] = INVALID_SOCKET;
  Events[i] = WSA_INVALID_EVENT;
 }
 ZeroMemory(recvBuffer, BUFFER_SIZE);
 WSAEVENT hEvent = WSACreateEvent();
 if(WSA_INVALID_EVENT == hEvent)
 {
  cout <<"WSACreateEvent Failed: " <<WSAGetLastError() <<endl;
  closesocket(Listen);
  WSACleanup();
     return;
 }
 
 nRet = WSAEventSelect(Listen, hEvent, FD_ACCEPT | FD_CLOSE);
 if (SOCKET_ERROR == nRet)
    {
     cout <<"WSAEventSelect Failed: " <<WSAGetLastError() <<endl;
  closesocket(Listen);
  WSACloseEvent(hEvent);
        WSACleanup();
        return;
    }  
 
 nRet = listen(Listen, 20);
 
    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"listen Failed: " <<WSAGetLastError() <<endl;
  WSACloseEvent(hEvent);
        WSACleanup();
        return;
    } 
   
 Sockets[dwTotal] = Listen;
 Events[dwTotal] = hEvent;
 dwTotal++;
 InterlockedIncrement(&dwClients);
 
 HANDLE hThread = CreateThread(NULL, 0, ThreadEvent, NULL, 0, NULL);
 if(NULL == hThread)
 {
  closesocket(Listen);
  cout <<"CreateThread Failed: " <<GetLastError() <<endl;
  WSACloseEvent(hEvent);
        WSACleanup();
        return;
    }
    CloseHandle(hThread);

    cout <<"Enter ‘q’ to exit: " <<endl;
    while(getch() != ‘q’);
    for(int j=1; i<WSA_MAXIMUM_WAIT_EVENTS; i++)
 {
  closesocket(Sockets[i]);
  WSACloseEvent(Events[i]);
 }
 cout <<"Main thread will exit " <<endl;
 WSACleanup();
 getch();
}

DWORD WINAPI ThreadEvent(LPVOID lpParam)
{
 WSAEVENT  Event, Temp;
 SOCKET  Socket;
 DWORD  dwRet;
 DWORD  Index;
 DWORD  dwIndex;
 WSANETWORKEVENTS netEvent;
 int     nRet;

 while(TRUE) 
 { 
  Event = WSA_INVALID_EVENT;
  Socket = INVALID_SOCKET;
  ZeroMemory(&netEvent, sizeof(WSANETWORKEVENTS));
  
  dwRet  =  WSAWaitForMultipleEvents(dwTotal,  Events,  FALSE,  WSA_INFINITE,  FALSE); 
  
  if(WSA_WAIT_FAILED  == dwRet) 
  { 
     cout <<"WSAWaitForMultipleEvents Failed: " <<WSAGetLastError() <<endl;
     break; 
  } 
  Index = dwRet – WSA_WAIT_EVENT_0;
  Event = Events[Index];
  Socket = Sockets[Index];
  if(INVALID_SOCKET == Socket)
  {
   WSAResetEvent(Event);
   continue;
  }
  nRet = WSAEnumNetworkEvents(Socket, Event, &netEvent);
  WSAResetEvent(Event); 
  if (SOCKET_ERROR == nRet)
     {
   closesocket(Socket);
   Sockets[Index] = INVALID_SOCKET;
   cout <<"WSAEnumNetworkEvents Failed: " <<WSAGetLastError() <<endl;
   InterlockedDecrement(&dwClients);
   cout <<"Client disconnected with socket: " <<Socket <<"  Total = " <<dwClients-1 <<endl;
   continue;
     } 
    
  if(netEvent.lNetworkEvents & FD_ACCEPT)
  {
   if(netEvent.iErrorCode[FD_ACCEPT_BIT] != 0)
   {
    cout <<"FD_ACCEPT failed: " <<netEvent.iErrorCode[FD_ACCEPT_BIT] <<endl;
    break;
   }
   
   SOCKET client = accept(Socket, NULL, NULL);
   if(client == INVALID_SOCKET)
   {
    cout <<"accept Failed: " <<WSAGetLastError() <<endl;
          break;
         }
        
   if(dwTotal >= WSA_MAXIMUM_WAIT_EVENTS)
   {
    dwIndex = GetInvalidIndex();
    if(-1 == dwIndex)
    {
           cout <<"Too many connections " <<endl;
           closesocket(client);
           continue;
    }
   }
   else
   {
    dwIndex = dwTotal; 
   }
   
   WSAEVENT hEvent = WSACreateEvent();
   if(WSA_INVALID_EVENT == hEvent)
   {
    cout <<"WSACreateEvent Failed: " <<WSAGetLastError() <<endl;
    closesocket(client);
       continue;
   }
   
   nRet = WSAEventSelect(client, hEvent, FD_READ | FD_WRITE | FD_CLOSE);
   if (SOCKET_ERROR == nRet)
      {
       cout <<"WSAEventSelect Failed: " <<WSAGetLastError() <<endl;
    closesocket(client);
    WSACloseEvent(hEvent);
          continue;
      }
     
      Sockets[dwIndex] = client;
      Temp = Events[dwIndex];
   Events[dwIndex] = hEvent;
   if(WSA_INVALID_EVENT != Temp)
   {
    WSACloseEvent(Temp);
   }
   if(dwTotal < WSA_MAXIMUM_WAIT_EVENTS) dwTotal++;  
   InterlockedIncrement(&dwClients);
   
   cout <<"Client connected with socket: " <<client <<"  Total = " <<dwClients-1 <<endl;
  }
  
  if(netEvent.lNetworkEvents & FD_READ)
  {
   if(netEvent.iErrorCode[FD_READ_BIT] != 0)
   {
    cout <<"FD_READ failed: " <<netEvent.iErrorCode[FD_READ_BIT] <<endl;
    closesocket(Socket);
    Sockets[Index] = INVALID_SOCKET;
    InterlockedDecrement(&dwClients);
    cout <<"Client disconnected with socket: " <<Socket <<"  Total = " <<dwClients-1 <<endl;
    continue;
   }
   ZeroMemory(recvBuffer, BUFFER_SIZE);
   nRet = recv(Socket, recvBuffer, BUFFER_SIZE, 0);
   if (SOCKET_ERROR == nRet)
      {
       cout <<"recv Failed: " <<WSAGetLastError() <<endl;
    closesocket(Socket);
    Sockets[Index] = INVALID_SOCKET;
    InterlockedDecrement(&dwClients);
    cout <<"Client disconnected with socket: " <<Socket <<"  Total = " <<dwClients-1 <<endl;
          continue;
      }
     
      cout <<"Recv: " <<recvBuffer <<endl;
  }
  
  if(netEvent.lNetworkEvents & FD_WRITE)
  {
   if(netEvent.iErrorCode[FD_WRITE_BIT] != 0)
   {
    cout <<"FD_WRITE failed: " <<netEvent.iErrorCode[FD_WRITE_BIT] <<endl;
    closesocket(Socket);
    Sockets[Index] = INVALID_SOCKET;
    InterlockedDecrement(&dwClients);
    cout <<"Client disconnected with socket: " <<Socket <<"  Total = " <<dwClients-1 <<endl;
    continue;
   }
   
   nRet = send(Socket, sendBuffer, strlen(sendBuffer), 0);
   if (SOCKET_ERROR == nRet)
      {
       cout <<"send Failed: " <<WSAGetLastError() <<endl;
    closesocket(Socket);
    Sockets[Index] = INVALID_SOCKET;
    InterlockedDecrement(&dwClients);
    cout <<"Client disconnected with socket: " <<Socket <<"  Total = " <<dwClients-1 <<endl;
          continue;
      }
     
      cout <<"Send: " <<sendBuffer <<endl;
  }
  
  if(netEvent.lNetworkEvents & FD_CLOSE)
  {
   if(netEvent.iErrorCode[FD_CLOSE_BIT] != 0)
   {
    cout <<"FD_CLOSE failed: " <<netEvent.iErrorCode[FD_CLOSE_BIT] <<endl;
    //continue;
   }
   
   closesocket(Socket);
   Sockets[Index] = INVALID_SOCKET;
   if(Socket != Listen) InterlockedDecrement(&dwClients);
   cout <<"Client disconnected socket: " <<Socket <<"  Total = " <<dwClients-1 <<endl;
  }
 }
 
 cout <<"ThreadEvent exit… " <<endl;
 return 0;
}

DWORD GetInvalidIndex()
{
 for(int i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++)
 {
  if(Sockets[i] == INVALID_SOCKET)
   return i;
 }
 return -1;
}

2005年06月10日

/*
 WinSock I/O Module
  —Overlapped IO Module
 Server Example 1.0  
 
 Author: yaliao [lya_118@163.com]
*/

#include <winsock2.h>
#include <mswsock.h>
#include <iostream.h>
#include <conio.h>

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

#define    BUFFER_SIZE           4096

SOCKET Sockets[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT Events[WSA_MAXIMUM_WAIT_EVENTS];
WSAOVERLAPPED Overlappeds[WSA_MAXIMUM_WAIT_EVENTS];
char sBuffer[WSA_MAXIMUM_WAIT_EVENTS][BUFFER_SIZE];

SOCKET Listen;
DWORD dwTotal = 0;
volatile long dwClients = 0;
HANDLE hThread;

DWORD GetInvalidIndex(); 
DWORD WINAPI ThreadAccept(LPVOID lpParam);
DWORD  WINAPI  WorkerThread(LPVOID  lpParam);

char sendBuffer[] = "\t Welcome to Overlapped IO Module server\r\n";

void main()
{
 WSADATA wsaData;

 int nRet;
 
 nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
 if(nRet != 0)
 {
  cout <<"WSAStartup Failed: " <<WSAGetLastError() <<endl;
  return;
 }

 Listen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
 
    if (INVALID_SOCKET == Listen)
    {
  cout <<"WSASocket Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        return;
    }
   
    SOCKADDR_IN inAddr;
   
    inAddr.sin_family = AF_INET;
 inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 inAddr.sin_port = htons(5150);  

    nRet = bind(Listen, (PSOCKADDR)&inAddr, sizeof(inAddr));

    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"bind Failed: " <<WSAGetLastError() <<endl;
  WSACleanup();
        return;
    } 
 
 nRet = listen(Listen, 20);
 
    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"listen Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        return;
    } 
   
    for(int i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++)
 {
  Sockets[i] = INVALID_SOCKET;
  Events[i] = WSA_INVALID_EVENT;
  ZeroMemory(&(Overlappeds[i]), sizeof(WSAOVERLAPPED));
  ZeroMemory(&sBuffer[i], BUFFER_SIZE);
 }
 
 hThread = CreateThread(NULL, 0, ThreadAccept, NULL, 0, NULL);
 if(NULL == hThread)
 {
  closesocket(Listen);
  cout <<"CreateThread Failed: " <<GetLastError() <<endl;
        WSACleanup();
        return;
    }
    CloseHandle(hThread);
   
    hThread = CreateThread(NULL, 0, WorkerThread, NULL, CREATE_SUSPENDED, NULL);
 if(NULL == hThread)
 {
  closesocket(Listen);
  cout <<"CreateThread Failed: " <<GetLastError() <<endl;
        WSACleanup();
        return;
    }
 
    cout <<"Enter ‘q’ to exit: " <<endl;
    while(getch() != ‘q’);
    closesocket(Listen);
    WSACleanup();
    CloseHandle(hThread);
 cout <<"Main thread will exit " <<endl;
 getch();
}

DWORD GetInvalidIndex()
{
 for(int i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++)
 {
  if(Sockets[i] == INVALID_SOCKET)
   return i;
 }
 return -1;
}

DWORD WINAPI ThreadAccept(LPVOID lpParam)
{
 SOCKET client;
 int nRet;
 WSAEVENT hEvent, Temp;
 WSABUF  wsaBuf;
 DWORD dwRecv;
 DWORD dwSend;
 DWORD dwFlag;
 DWORD dwIndex = -1;

 while(true)
 {
  client = WSAAccept(Listen, NULL, NULL, NULL, 0);
  
  if(client == INVALID_SOCKET)
  {
   cout <<"WSAAccept Failed: " <<WSAGetLastError() <<endl;
   cout <<"ThreadAccept thread exit " <<endl;
         return 0;
        }
  if(dwTotal >= WSA_MAXIMUM_WAIT_EVENTS)
  {
   dwIndex = GetInvalidIndex();
   if(-1 == dwIndex)
   {
          cout <<"Too many connections " <<endl;
          closesocket(client);
          continue;
   }
  }
  else
  {
   dwIndex = dwTotal;
  }
       
  hEvent = WSACreateEvent();
  if(WSA_INVALID_EVENT == hEvent)
  {
   cout <<"WSACreateEvent Failed: " <<WSAGetLastError() <<endl;
   closesocket(client);
         return 0;
  }
  
  Sockets[dwIndex] = client;
  Temp = Events[dwIndex];
  Events[dwIndex] = hEvent;
  if(WSA_INVALID_EVENT != Temp)
  {
   WSACloseEvent(Temp);
  }

  ZeroMemory(&(Overlappeds[dwIndex]), sizeof(WSAOVERLAPPED));
  ZeroMemory(&sBuffer[dwIndex], BUFFER_SIZE);
  Overlappeds[dwIndex].hEvent = hEvent;
  wsaBuf.buf = sBuffer[dwIndex];
  wsaBuf.len = BUFFER_SIZE;
  dwRecv = 0;
  dwFlag = 0;

  nRet = WSARecv(client, &wsaBuf, 1, &dwRecv,  &dwFlag, &(Overlappeds[dwIndex]), NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
    closesocket(client);
    Sockets[dwIndex] = INVALID_SOCKET;
    ZeroMemory(&(Overlappeds[dwIndex]), sizeof(WSAOVERLAPPED));
    ZeroMemory(&(sBuffer[dwIndex]), BUFFER_SIZE);
    continue;
   }
  }
  
  ZeroMemory(&(Overlappeds[dwIndex]), sizeof(WSAOVERLAPPED));
  wsaBuf.buf = sendBuffer;
  wsaBuf.len = strlen(sendBuffer);
  dwSend = 0;
  dwFlag = 0;
  
  nRet = WSASend(client, &wsaBuf, 1, &dwSend,  dwFlag, &(Overlappeds[dwIndex]), NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSASend Failed: " <<WSAGetLastError() <<endl;
    closesocket(client);
    Sockets[dwIndex] = INVALID_SOCKET;
    ZeroMemory(&(Overlappeds[dwIndex]), sizeof(WSAOVERLAPPED));
    ZeroMemory(&(sBuffer[dwIndex]), BUFFER_SIZE);
    continue;
   }
  }
  
  if(dwTotal < WSA_MAXIMUM_WAIT_EVENTS) dwTotal++;
  InterlockedIncrement(&dwClients);
  if(dwClients == 1) ResumeThread(hThread);
  cout <<"Client connected with socket: " <<client <<"  Total = " <<dwClients <<endl;
  cout <<"Send: " <<wsaBuf.buf <<endl;
 }
}

DWORD  WINAPI  WorkerThread(LPVOID  lpParam) 

    DWORD  dwEvent;
 DWORD  Index;
 WSABUF  wsaBuf;
 DWORD dwRecv;
 DWORD dwSend;
 DWORD dwFlag;
 int     nRet;
 //WSAOVERLAPPED ol;

 while(TRUE) 
 { 
  dwEvent  =  WSAWaitForMultipleEvents(dwTotal,  Events,  FALSE,  10/*WSA_INFINITE*/,  FALSE); 
  
  if(WSA_WAIT_TIMEOUT  == dwEvent) 
  { 
   continue;
  } 
  
  if(WSA_WAIT_FAILED  == dwEvent) 
  { 
    cout <<"WSAWaitForMultipleEvents Failed: " <<WSAGetLastError() <<endl;
    return 0; 
  } 
  
  Index =  dwEvent – WSA_WAIT_EVENT_0;
  WSAResetEvent(Events[Index]); 
  
  DWORD dwBytes = 0;
  DWORD dwFlags = 0;
  WSAGetOverlappedResult(Sockets[Index], &(Overlappeds[Index]), &dwBytes, FALSE, &dwFlags);
  
  if(dwBytes == 0)
  {
   cout <<"Client disconnected: " <<Sockets[Index] <<endl;
   ZeroMemory(&(Overlappeds[Index]), sizeof(WSAOVERLAPPED));
   ZeroMemory(&(sBuffer[Index]), BUFFER_SIZE);
   closesocket(Sockets[Index]);
   Sockets[Index] = INVALID_SOCKET;
   InterlockedDecrement(&dwClients);
   if(dwClients == 0) SuspendThread(hThread);
   continue;
  }

  cout<<"Recv: " <<sBuffer[Index] <<endl;
  /*
  ZeroMemory(&ol, sizeof(WSAOVERLAPPED));
  wsaBuf.buf = sBuffer[Index];
  wsaBuf.len = BUFFER_SIZE;
  dwRecv = 0;
  dwSend = 0;
  dwFlag = 0;
  
  nRet = WSASend(Sockets[Index], &wsaBuf, 1, &dwSend, dwFlag, &ol, NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
    closesocket(Sockets[Index]);
    Sockets[Index] = INVALID_SOCKET;
    continue;
   }
  }
  */
  ZeroMemory(&(Overlappeds[Index]), sizeof(WSAOVERLAPPED));
  ZeroMemory(&sBuffer[Index], BUFFER_SIZE);
  Overlappeds[Index].hEvent = Events[Index];
  wsaBuf.buf = sBuffer[Index];
  wsaBuf.len = BUFFER_SIZE;
  dwRecv = 0;
  dwSend = 0;
  dwFlag = 0;

  nRet = WSARecv(Sockets[Index], &wsaBuf, 1, &dwRecv,  &dwFlag, &(Overlappeds[Index]), NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
    ZeroMemory(&(Overlappeds[Index]), sizeof(WSAOVERLAPPED));
    ZeroMemory(&(sBuffer[Index]), BUFFER_SIZE);
    closesocket(Sockets[Index]);
    Sockets[Index] = INVALID_SOCKET;
    InterlockedDecrement(&dwClients); 
    if(dwClients == 0) SuspendThread(hThread);   
    continue;
   }
  }
 }

2005年06月03日

/*
 Monitor File Change Infomation
  —Completion Port Module
 Monitor Example 1.0  适用于监控一个目录
 
 Author: yaliao [lya_118@163.com]
*/
#include <windows.h>
#include <iostream.h>
#include <conio.h>

#define MAX_BUFFER  4096
//
//自定义结构,即“完成键”(单句柄数据)
//
typedef struct _PER_IO_CONTEXT
{
 OVERLAPPED              ol;
 HANDLE                     hDir;
 CHAR        lpBuffer[MAX_BUFFER];
 _PER_IO_CONTEXT*           pNext;
}PER_IO_CONTEXT, *PPER_IO_CONTEXT;

PPER_IO_CONTEXT g_pIContext;

typedef BOOL (WINAPI *lpReadDirectoryChangesW)( HANDLE,
        LPVOID,
        DWORD,
        BOOL,
        DWORD,
        LPDWORD,
        LPOVERLAPPED,
        LPOVERLAPPED_COMPLETION_ROUTINE);
       
lpReadDirectoryChangesW ReadDirectoryChangesW = NULL;

HANDLE g_hIocp;
HANDLE g_hDir;
 
DWORD WINAPI CompletionRoutine(LPVOID lpParam);
void FileActionRoutine(PFILE_NOTIFY_INFORMATION pfi);
TCHAR szDirectory[] = "c:\\";

void main()
{
 HANDLE hRet;
 HANDLE hThread;
 
 g_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
 if (NULL == g_hIocp)
 {
  cout <<"CreateIoCompletionPort Failed: " <<GetLastError() <<endl;
  return;
 }
 cout <<"monitor directory is: " <<szDirectory <<endl;
 g_hDir = CreateFile(  szDirectory,
      FILE_LIST_DIRECTORY,
      FILE_SHARE_READ|
      FILE_SHARE_WRITE|
      FILE_SHARE_DELETE,
      NULL,
      OPEN_EXISTING,
      FILE_FLAG_BACKUP_SEMANTICS|
      FILE_FLAG_OVERLAPPED,
      NULL);
 if (NULL == g_hDir)
 {
  cout <<"CreateFile Failed: " <<GetLastError() <<endl;
  CloseHandle(g_hIocp);
  return;
 }
 
 HINSTANCE hInst = LoadLibrary("Kernel32.DLL");
 if(!hInst)
 {
  cout <<"LoadLibrary Failed: " <<GetLastError() <<endl;
  CloseHandle(g_hIocp);
  CloseHandle(g_hDir);
  return;
 }
 
 ReadDirectoryChangesW = (lpReadDirectoryChangesW)GetProcAddress(hInst, "ReadDirectoryChangesW");//获取DLL函数入口
 FreeLibrary(hInst); 
 
 SYSTEM_INFO SysInfo;
 GetSystemInfo(&SysInfo);
 for (int i=0; i<(int)SysInfo.dwNumberOfProcessors; i++)
 {
  hThread = CreateThread(NULL, 0, CompletionRoutine, NULL, 0, NULL);
  if(NULL == hThread)
  {
   cout <<"CreateThread Failed: " <<GetLastError() <<endl;
   CloseHandle(g_hIocp);
      CloseHandle(g_hDir);
   return;
  }
  CloseHandle(hThread);
 }

 g_pIContext = (PPER_IO_CONTEXT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
 if(NULL == g_pIContext)
 {
  cout <<"HeapAlloc Failed: " <<GetLastError() <<endl;
  PostQueuedCompletionStatus(g_hIocp, 0, NULL, NULL);
     CloseHandle(g_hIocp);
     CloseHandle(g_hDir);
  return;
 }
 g_pIContext->hDir = g_hDir;
 ZeroMemory(&(g_pIContext->ol), sizeof(OVERLAPPED));
 ZeroMemory(g_pIContext->lpBuffer, MAX_BUFFER);
 g_pIContext->pNext = NULL;
   
 hRet = CreateIoCompletionPort(g_hDir, g_hIocp, (ULONG_PTR)g_pIContext, 0);
 if(NULL == hRet)
 {
  cout <<"CreateIoCompletionPort Failed: " <<GetLastError() <<endl;
  PostQueuedCompletionStatus(g_hIocp, 0, NULL, NULL);
     CloseHandle(g_hIocp);
     CloseHandle(g_hDir);
     HeapFree(GetProcessHeap(), 0, g_pIContext);
  return;
 }
 
 DWORD nBytes = 0;
 BOOL  bRet = FALSE;

 bRet = ReadDirectoryChangesW(g_pIContext->hDir,
      g_pIContext->lpBuffer,
      MAX_BUFFER,
      TRUE,
      FILE_NOTIFY_CHANGE_FILE_NAME |
      FILE_NOTIFY_CHANGE_DIR_NAME |
      FILE_NOTIFY_CHANGE_ATTRIBUTES |
      FILE_NOTIFY_CHANGE_SIZE |
      FILE_NOTIFY_CHANGE_LAST_ACCESS |
      FILE_NOTIFY_CHANGE_CREATION |
      FILE_NOTIFY_CHANGE_SECURITY |
               FILE_NOTIFY_CHANGE_LAST_WRITE,
      &nBytes,
      &(g_pIContext->ol),
      NULL);
 if(!bRet)
 {
  cout <<"ReadDirectoryChangesW Failed: " <<GetLastError() <<endl;
  PostQueuedCompletionStatus(g_hIocp, 0, NULL, NULL);
     CloseHandle(g_hIocp);
     CloseHandle(g_hDir);
     HeapFree(GetProcessHeap(), 0, g_pIContext);
  return;
 }
 cout <<"Enter q to exit: " <<endl;
    while(getch() != ‘q’);
   
 PostQueuedCompletionStatus(g_hIocp, 0, NULL, NULL);
 CloseHandle(g_hIocp);
 CloseHandle(g_hDir);
 HeapFree(GetProcessHeap(), 0, g_pIContext);
 cout <<"Main thread will exit " <<endl;
 getch();
}

DWORD WINAPI CompletionRoutine(LPVOID lpParam)
{
 DWORD dwBytes;
 PPER_IO_CONTEXT pIContext = NULL;
 LPOVERLAPPED pOL = NULL;
 PFILE_NOTIFY_INFORMATION pfi = NULL;
 BOOL bRet;
 DWORD cbOffset;
 DWORD nBytes;
 while(true)
 {
  bRet = GetQueuedCompletionStatus(g_hIocp, &dwBytes,(PULONG_PTR )&pIContext, &pOL, INFINITE);

  if(bRet)
  {
   if(NULL == pIContext)
   {
    cout <<"CompletionRoutine thread exit " <<endl;
    return 0;
   }
   
   pfi = (PFILE_NOTIFY_INFORMATION)pIContext->lpBuffer;
   
   do
         {
    try
    {
     switch(pfi->Action)
     {
      case FILE_ACTION_ADDED: //The file was added to the directory.
       cout <<"FILE_ACTION_ADDED: ";
       FileActionRoutine(pfi);
       break;
      case FILE_ACTION_REMOVED: //The file was removed from the directory.
       cout <<"FILE_ACTION_REMOVED: ";
       FileActionRoutine(pfi);
       break;
      case FILE_ACTION_MODIFIED: //The file was modified. This can be a change in the time stamp or attributes.
       cout <<"FILE_ACTION_MODIFIED: ";
       FileActionRoutine(pfi);
       break;
      case FILE_ACTION_RENAMED_OLD_NAME: //The file was renamed and this is the old name.
       cout <<"FILE_ACTION_RENAMED_OLD_NAME: ";
       FileActionRoutine(pfi);
       break;
      case FILE_ACTION_RENAMED_NEW_NAME: //The file was renamed and this is the new name.
       cout <<"FILE_ACTION_RENAMED_NEW_NAME: ";
       FileActionRoutine(pfi);
       break;
      default:
       break;

     }
     cbOffset = pfi->NextEntryOffset;//一次消息中包含了多个文件变化的信息吗?
     pfi = (PFILE_NOTIFY_INFORMATION)((LPBYTE) pfi + cbOffset);
    }
    catch(…)
    {
     LPVOID lpMsgBuf;
     FormatMessage( //把错误消息格式化
         FORMAT_MESSAGE_ALLOCATE_BUFFER |
         FORMAT_MESSAGE_FROM_SYSTEM |
         FORMAT_MESSAGE_IGNORE_INSERTS,
         NULL,
         GetLastError(), //错误消息
         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
         (LPTSTR) &lpMsgBuf, //格式化后的错误消息
         0,
         NULL
        );
     cout <<"CompletionRoutine Exception = " <<lpMsgBuf <<endl;
     LocalFree(lpMsgBuf);
    }
         }while(cbOffset);
  }
  
  g_pIContext->hDir = g_hDir;
  ZeroMemory(&(g_pIContext->ol), sizeof(OVERLAPPED));
  ZeroMemory(g_pIContext->lpBuffer, MAX_BUFFER);
  g_pIContext->pNext = NULL;
  
  nBytes = 0;
  bRet = FALSE;

  bRet = ReadDirectoryChangesW(g_pIContext->hDir,
       g_pIContext->lpBuffer,
       MAX_BUFFER,
       TRUE,
       FILE_NOTIFY_CHANGE_FILE_NAME |
       FILE_NOTIFY_CHANGE_DIR_NAME |
       FILE_NOTIFY_CHANGE_ATTRIBUTES |
       FILE_NOTIFY_CHANGE_SIZE |
       FILE_NOTIFY_CHANGE_LAST_ACCESS |
       FILE_NOTIFY_CHANGE_CREATION |
       FILE_NOTIFY_CHANGE_SECURITY |
                FILE_NOTIFY_CHANGE_LAST_WRITE,
       &nBytes,
       &(g_pIContext->ol),
       NULL);
  if(!bRet)
  {
   cout <<"ReadDirectoryChangesW Failed: " <<GetLastError() <<endl;
   return 0;
  }
 }
}

void FileActionRoutine(PFILE_NOTIFY_INFORMATION pfi)
{
    TCHAR szFileName[MAX_PATH];
    memset(szFileName,’\0′,sizeof(szFileName));
    WideCharToMultiByte(CP_ACP, //ANSI码
      0,
      pfi->FileName,   //待转换的字符串
      pfi->FileNameLength/2,
      szFileName,     //转换后的字符串
      MAX_PATH,
      NULL,
      NULL);
    cout <<szFileName <<endl;
}

2005年06月01日

/*
 WinSock I/O Module
  —Module Socket Example Test
 Client Test 1.0  
 
 Author: yaliao [lya_118@163.com]
*/
#include <winsock2.h>
#include <mswsock.h>
#include <stdio.h>
#include <conio.h>

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

#define S_ADDR "10.21.18.38"
#define S_PORT 5150
#define BUFFER_SIZE 255

char szBuf[] = "client send data";
 
DWORD WINAPI ThreadRoutine(LPVOID lpParam);

void main()
{
 WSADATA wsaData;
 int nRet;
 HANDLE hThread;
 int nCout=0;

 nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
 if(nRet != 0)
 {
  printf("WSAStartup Failed: %d\n", WSAGetLastError());
  return;
 }

 HANDLE hEvent;
 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 if(NULL == hEvent)
 {
  printf("CreateEvent Failed: %d\n", GetLastError());
  WSACleanup();
  return;
 }
 printf("Thread Cout =     ");
 while(true)
 {
  hThread = CreateThread(NULL, 0, ThreadRoutine, &hEvent, 0, NULL);
  if(NULL != hThread)
  {
   nCout++;
   CloseHandle(hThread);
   printf("\b\b\b\b%4d", nCout);
  }
  if(nCout >= 2000)
   break;
 }
 getch();
 SetEvent(hEvent);
 getch();
 WSACleanup();
}

DWORD WINAPI ThreadRoutine(LPVOID lpParam)
{
 HANDLE hEvent = *(HANDLE*)lpParam;
 SOCKET client;
 client = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
 
    if (INVALID_SOCKET == client)
    {
     //printf("WSASocket Failed: %d\n", WSAGetLastError());
        return 0;
    }
   
    SOCKADDR_IN inAddr;
   
    inAddr.sin_family = AF_INET;
 inAddr.sin_addr.s_addr = inet_addr(S_ADDR);
 inAddr.sin_port = htons(S_PORT);  
 
    WSABUF wsaBuf;
    wsaBuf.buf = szBuf;
    wsaBuf.len = strlen(szBuf);
    //FLOWSPEC fSpec;
   
    int nRet;
    nRet = WSAConnect(client, (PSOCKADDR)&inAddr, sizeof(inAddr), NULL, NULL, NULL, NULL);
   
    if (SOCKET_ERROR == nRet)
    {
     //printf("WSAConnect Failed: %d\n", WSAGetLastError());
     closesocket(client);
        return 0;
    }
    DWORD nFlag = 0;
    DWORD nSend = 0;
   
    nRet = WSASend(client, &wsaBuf, 1, &nSend, nFlag, NULL, NULL);
   
    if (SOCKET_ERROR == nRet)
    {
     //printf("WSASend Failed: %d\n", WSAGetLastError());
     closesocket(client);
  return 0;
    }
 WaitForSingleObject(hEvent, INFINITE);
 closesocket(client);
 printf("ThreadRoutine exit\n");
 return 0;
}

/*
 WinSock I/O Module
  —Completion Port Module
 Server Example 1.0  
 
 Author: yaliao [lya_118@163.com]
*/
#include <winsock2.h>
#include <mswsock.h>
#include <iostream.h>
#include <conio.h>

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

HANDLE hIocp;
SOCKET Listen;

//
//自定义结构,即“完成键”(单句柄数据)
//
typedef struct _PER_HANDLE_CONTEXT
{
 SOCKET                     client;
 _PER_HANDLE_CONTEXT*       pNext;
}PER_HANDLE_CONTEXT, *PPER_HANDLE_CONTEXT;

#define    BUFFER_SIZE           4096

typedef enum _IO_OPERATION
{
  RECV = 1, 
  SEND
}IO_OPERATION, *PIO_OPERATION;

typedef struct _PER_IO_CONTEXT
{
 WSAOVERLAPPED              ol;
 WSABUF                     wsaBuffer;
 CHAR                       szBuffer[BUFFER_SIZE];
 IO_OPERATION               OpType;
 _PER_IO_CONTEXT*           pNext;
}PER_IO_CONTEXT, *PPER_IO_CONTEXT;

DWORD WINAPI CompletionRoutine(LPVOID lpParam);
DWORD WINAPI ThreadAccept(LPVOID lpParam);

char sendBuffer[] = "\t Welcome to Completion Port IO Module server\r\n";

void main()
{
 WSADATA wsaData;
 int nRet;
 HANDLE hThread;
 
 nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
 if(nRet != 0)
 {
  cout <<"WSAStartup Failed: " <<WSAGetLastError() <<endl;
  return;
 }

 hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
 if (NULL == hIocp)
 {
  cout <<"CreateIoCompletionPort Failed: " <<GetLastError() <<endl;
  WSACleanup();
  return;
 }
 
 SYSTEM_INFO SysInfo;
 GetSystemInfo(&SysInfo);
 for (int i=0; i<(int)SysInfo.dwNumberOfProcessors; i++)
 {
  hThread = CreateThread(NULL, 0, CompletionRoutine, NULL, 0, NULL);
  if(NULL == hThread)
  {
   cout <<"CreateThread Failed: " <<GetLastError() <<endl;
   WSACleanup();
   CloseHandle(hIocp);
   return;
  }
  CloseHandle(hThread);
 }
 
 Listen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
 
    if (INVALID_SOCKET == Listen)
    {
  cout <<"WSASocket Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
        CloseHandle(hIocp);
        return;
    }
   
    SOCKADDR_IN inAddr;
   
    inAddr.sin_family = AF_INET;
 inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 inAddr.sin_port = htons(5150);  

    nRet = bind(Listen, (PSOCKADDR)&inAddr, sizeof(inAddr));

    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"bind Failed: " <<WSAGetLastError() <<endl;
  WSACleanup();
  PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
  CloseHandle(hIocp);
        return;
    } 

 nRet = listen(Listen, 20);
 
    if (SOCKET_ERROR == nRet)
    {
  closesocket(Listen);
  cout <<"listen Failed: " <<WSAGetLastError() <<endl;
        WSACleanup();
        PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
        CloseHandle(hIocp);
        return;
    } 
     
 hThread = CreateThread(NULL, 0, ThreadAccept, NULL, 0, NULL);
 if(NULL == hThread)
 {
  closesocket(Listen);
  cout <<"CreateThread Failed: " <<GetLastError() <<endl;
        WSACleanup();
        PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
        CloseHandle(hIocp);
        return;
    }
    CloseHandle(hThread);
    cout <<"Enter ‘q’ to exit: " <<endl;
    while(getch() != ‘q’);
    closesocket(Listen);
    WSACleanup();
    PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
    CloseHandle(hIocp);
 cout <<"Main thread will exit " <<endl;
 getch();
}

DWORD WINAPI ThreadAccept(LPVOID lpParam)
{
 SOCKET client;
 PPER_HANDLE_CONTEXT pHContext;
 HANDLE hRet;
 PPER_IO_CONTEXT pIContext;
 int nRet;
 
 while(true)
 {
  client = WSAAccept(Listen, NULL, NULL, NULL, 0);
  
  if(client == INVALID_SOCKET)
  {
   cout <<"WSAAccept Failed: " <<WSAGetLastError() <<endl;
   cout <<"ThreadAccept thread exit " <<endl;
         return 0;
        }
  pHContext = (PPER_HANDLE_CONTEXT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(PER_HANDLE_CONTEXT));
  if(NULL == pHContext)
  {
   cout <<"HeapAlloc Failed: " <<GetLastError() <<endl;
   closesocket(client);
   continue;
  }
  pHContext->client = client;
  pHContext->pNext = NULL;
  hRet = CreateIoCompletionPort((HANDLE)client, hIocp, (ULONG_PTR)pHContext, 0);
  if(NULL == hRet)
  {
   cout <<"CreateIoCompletionPort Failed: " <<GetLastError() <<endl;
   closesocket(client);
   HeapFree(GetProcessHeap(), 0, pHContext);
   continue;
  }
  pIContext = (PPER_IO_CONTEXT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
  if(NULL == pIContext)
  {
   cout <<"HeapAlloc Failed: " <<GetLastError() <<endl;
   closesocket(client);
   HeapFree(GetProcessHeap(), 0, pHContext);
   continue;
  }
  ZeroMemory(&(pIContext->ol), sizeof(pIContext->ol));
  ZeroMemory(pIContext->szBuffer, BUFFER_SIZE);
  pIContext->wsaBuffer.buf = pIContext->szBuffer;
  pIContext->wsaBuffer.len = BUFFER_SIZE;
  pIContext->OpType = RECV;
  pIContext->pNext = NULL;
  
  DWORD nRecv = 0;
  DWORD nFlag = 0;

  nRet = WSARecv(pHContext->client, &(pIContext->wsaBuffer), 1, &nRecv, &nFlag, &(pIContext->ol), NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
    closesocket(pHContext->client);
    HeapFree(GetProcessHeap(), 0, pHContext);
    HeapFree(GetProcessHeap(), 0, pIContext);
    continue;
   }
  }
  
  ZeroMemory(&(pIContext->ol), sizeof(pIContext->ol));
  pIContext->wsaBuffer.buf = sendBuffer;
  pIContext->wsaBuffer.len = strlen(sendBuffer);
  pIContext->OpType = SEND;
  pIContext->pNext = NULL;
  
  DWORD nSend = 0;
  nFlag = 0;
  nRet = WSASend(pHContext->client, &(pIContext->wsaBuffer), 1, &nSend, nFlag, &(pIContext->ol), NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSASend Failed: " <<WSAGetLastError() <<endl;
    closesocket(pHContext->client);
    HeapFree(GetProcessHeap(), 0, pHContext);
    HeapFree(GetProcessHeap(), 0, pIContext);
    continue;
   }
  }
  cout <<"Client connected with socket: " <<pHContext->client <<endl;
 }
}

DWORD WINAPI CompletionRoutine(LPVOID lpParam)
{
 DWORD dwBytes;
 PPER_HANDLE_CONTEXT pHContext = NULL;
 PPER_IO_CONTEXT pIContext = NULL;
 LPWSAOVERLAPPED pOL = NULL;
 int nRet;
 BOOL bRet;
 while(true)
 {
  bRet = GetQueuedCompletionStatus(hIocp, &dwBytes,(PULONG_PTR )&pHContext, &pOL, INFINITE);
  if(FALSE == bRet)
  {
   cout <<"GetQueuedCompletionStatus Failed: " <<GetLastError() <<endl;
   if((NULL != pOL) && (0 == dwBytes))
   {
    closesocket(pHContext->client);
    cout <<"Client disconnected socket: " <<pHContext->client <<endl;
    HeapFree(GetProcessHeap(), 0, pHContext);
    HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(pOL, PER_IO_CONTEXT, ol));
   }
   continue;
  }
  if(NULL == pHContext)
  {
   cout <<"CompletionRoutine thread exit " <<endl;
   return 0;
  }
  
  pIContext = CONTAINING_RECORD(pOL, PER_IO_CONTEXT, ol);
  
  if(0 == dwBytes)
  {
   closesocket(pHContext->client);
   cout <<"Client disconnected socket: " <<pHContext->client <<endl;
   HeapFree(GetProcessHeap(), 0, pHContext);
   HeapFree(GetProcessHeap(), 0, pIContext);
   continue;
  }
  
  switch(pIContext->OpType)
  {
   case RECV:
    cout << "Recv: " << pIContext->szBuffer << endl; 
    break;
   case SEND:
    cout << "Send: " << pIContext->wsaBuffer.buf << endl; 
    break;
   default:
    break;
  }
  
  ZeroMemory(&(pIContext->ol), sizeof(pIContext->ol));
  ZeroMemory(pIContext->szBuffer, BUFFER_SIZE);
  pIContext->wsaBuffer.buf = pIContext->szBuffer;
  pIContext->wsaBuffer.len = BUFFER_SIZE;
  pIContext->OpType = RECV;
  pIContext->pNext = NULL;
  
  DWORD nRecv = 0;
  DWORD nFlag = 0;

  nRet = WSARecv(pHContext->client, &(pIContext->wsaBuffer), 1, &nRecv, &nFlag, &(pIContext->ol), NULL);
  if(SOCKET_ERROR == nRet)
  {
   if(ERROR_IO_PENDING != WSAGetLastError())
   {
    cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
    closesocket(pHContext->client);
    HeapFree(GetProcessHeap(), 0, pHContext);
    HeapFree(GetProcessHeap(), 0, pIContext);
    continue;
   }
  }
 }
}

2005年05月26日
文章标题:一个从网上下载文件的类
原 作 者:Chris Maunder
原 出 处:CodeProject.com
发 布 者:loose_went
发布类型:翻译
发布日期:2004-10-18
今日浏览:8
总 浏 览:2665
下载本文所附源代码

程序运行效果截图:


CWebGrab类使您能够快速简洁的从网上下载文件。它支持所有MFC类支持的协议。
这个类使用起来很简单,你只需要调用一个主函数CWebGrab::GetFile。这个函数的语法是:
BOOL GetFile(LPCTSTR szURL, CString& strBuffer,
LPCTSTR szAgentName = NULL, CWnd* pWnd = NULL);

szURL–URL路径 。
strBuffer–是接受下载文件的字符串缓冲。
szAgentName–是你的代理服务器名称(可以是NULL)。
pWnd–是一个状态窗口,它的状态可以用函数SetWindowText()改变。


BOOL GetFileInfo(LPCTSTR szURL, CString& strLastModified, DWORD& dwSize,
DWORD& dwServerError, LPCTSTR szAgentName = NULL,
CWnd* pWnd = NULL);
得到给定URL地址的文件的信息。

szURL–URL路径 。
strLastModified–保存指定文件的最后修改日期的字符串缓冲。
dwServerError–返回的错误代码。
szAgentName–是你的代理服务器名称(可以是NULL)。
pWnd–是一个状态窗口,它的状态可以用函数SetWindowText()改变。


Bryce Burrows 加入了下面这些函数,是这个类更加强大:

void SetUseProxy(bool use);
设置是否使用代理服务器。

void SetProxyServer(LPCSTR server);
设置代理服务器名称。

void SetProxyPort(UINT port);
设置代理服务器端口。

void SetProxy(LPCSTR proxy, WORD port, bool use=true);
一次性设置代理服务器的信息。

void SetForceReload (bool bForceReload)
设置在下在一个文档时是否允许强行重新下载,如果允许,那么下载文档时将没有缓冲。

void GetForceReload()
得到是否允许强行重新下载。

void SetTimeOut(DWORD timeOut);
设置操作的允许时间。

double GetRate();
得到下载速率(Kb/sec)。

SHORT GetErrorCode();
CString GetErrorMessage();
得到错误的代码和消息。

下面是一个例子。
#include "webgrab.h"

void CWebGrabberDlg::OnDownload()
{
CString strBuffer;
CWebGrab grab;
if (grab.GetFile("http://www.mysite.com/index.htm", // the url
strBuffer, // buffer for data
_T("WebGrab demo"), // agent name
GetDlgItem(IDC_STATUS))) // Plain ol’ CStatic window
{
TRACE0("everything went OK ")
}
}

================================================================================

/////////////////////////////////////////////////////////////////////////////
// WebGrab.h : header file
//
// CWebGrab – CHttpFile wrapper class
//
// Written by Chris Maunder <cmaunder@mail.com>
// Copyright (c) 1998-2002. All Rights Reserved.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name and all copyright
// notices remains intact.
//
// An email letting me know how you are using it would be nice as well.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// History: 19 Nov 1999 – Release
//          26 Jan 2002 – Update by Bryce to include Proxy support and
//                        property accessors (transfer rate, error msg
//                        etc)
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_WEBGRAB_H__D31F39A4_1C63_11D3_AA11_AC48B5000000__INCLUDED_)
#define AFX_WEBGRAB_H__D31F39A4_1C63_11D3_AA11_AC48B5000000__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// WebGrab.h : header file
//

#include <afxinet.h>

/////////////////////////////////////////////////////////////////////////////
// CWebGrabSession

class CWebGrabSession : public CInternetSession
{
// Construction
public:
 CWebGrabSession(LPCTSTR szAgentName);
 CWebGrabSession(LPCTSTR szAgentName, CWnd* pStatusWnd);
 virtual ~CWebGrabSession();
    void CommonConstruct();

// Operations
public:
    void SetStatus(LPCTSTR fmt, …);
    void SetStatusWnd(CWnd* pWnd)     { m_pStatusWnd = pWnd; }

// Overrides
public:
 CString GetErrorMessage();
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CWebGrabSession)
 //}}AFX_VIRTUAL
    virtual void OnStatusCallback(DWORD dwContext, DWORD dwInternetStatus,
                                  LPVOID lpvStatusInformation,
                                  DWORD dwStatusInformationLength);

 // Generated message map functions
 //{{AFX_MSG(CWebGrabSession)
 //}}AFX_MSG

// Attributes
protected:
    CWnd* m_pStatusWnd;
 CString errorMessage;

};


/////////////////////////////////////////////////////////////////////////////
// CWebGrab

class CWebGrab : public CObject
{
public:
 CWebGrab();
 virtual ~CWebGrab();

// Operations
public:
    BOOL Initialise(LPCTSTR szAgentName = NULL, CWnd* pWnd = NULL);
 

    BOOL GetFile(LPCTSTR szURL, CString& strBuffer,
                 LPCTSTR szAgentName = NULL, CWnd* pWnd = NULL);

  void Close();
 // Overrides
public:
 CString GetRawHeaders();
 CString GetSocksHttp(LPCSTR url);
 CString GetErrorMessage();

 DWORD GetPageStatusCode();
 SHORT   GetErrorCode();
 double  GetRate();

 void    SetUseProxy(bool use);
 void    SetProxy(LPCSTR proxy, WORD port,bool use=true);
 void    SetProxyPort(UINT port);
 void    SetProxyServer(LPCSTR server);
 void    SetTimeOut(DWORD timeOut);

 

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CWebGrab)
 //}}AFX_VIRTUAL

 // Generated message map functions
 //{{AFX_MSG(CWebGrab))
 //}}AFX_MSG

protected:
    CWebGrabSession* m_pSession;
 DWORD   m_timeOut;

private:
 double  m_transferRate;
 bool    m_useProxy;
 UINT    m_Port;
 DWORD m_infoStatusCode;

 CString m_ErrorMessage;
 CString m_Proxy;
 CString m_rawHeaders;
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_WEBGRAB_H__D31F39A4_1C63_11D3_AA11_AC48B5000000__INCLUDED_)
===============================================================================

/////////////////////////////////////////////////////////////////////////////
// WebGrab.cpp : implementation file
//
// CWebGrab – CHttpFile wrapper class
//
// Written by Chris Maunder <cmaunder@mail.com>
// Copyright (c) 1998-2002. All Rights Reserved.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name and all copyright
// notices remains intact.
//
// An email letting me know how you are using it would be nice as well.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// History: 19 Nov 1999 – Release
//          26 Jan 2002 – Update by Bryce to include Proxy support and
//                        property accessors (transfer rate, error msg
//                        etc)
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "WebGrab.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define BUFFER_SIZE 4095

/////////////////////////////////////////////////////////////////////////////
// CWebGrab

CWebGrab::CWebGrab()
{
 m_pSession = NULL;
 m_timeOut = 0;
 m_useProxy = false;
 m_infoStatusCode=0;
}

CWebGrab::~CWebGrab()
{
    Close();
}

BOOL CWebGrab::Initialise(LPCTSTR szAgentName /*=NULL*/, CWnd* pWnd /*=NULL*/)
{
    Close();
 m_infoStatusCode=0;
    m_pSession = new CWebGrabSession(szAgentName, pWnd);

 if (m_timeOut != 0)
  m_pSession->SetOption(INTERNET_OPTION_DATA_RECEIVE_TIMEOUT  ,m_timeOut);

 // added Bryce
 if (m_useProxy)
 {
  char buf[10];
  itoa(m_Port,buf,10);
  CString temp = m_Proxy+":"+(CString)buf;
  INTERNET_PROXY_INFO proxyinfo;
  proxyinfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
  proxyinfo.lpszProxy = temp;
  proxyinfo.lpszProxyBypass = NULL;
  m_pSession->SetOption(INTERNET_OPTION_PROXY, (LPVOID)&proxyinfo, sizeof(INTERNET_PROXY_INFO));
 }

 
 return (m_pSession != NULL);
}

void CWebGrab::Close()
{
    if (m_pSession)
    {
        m_pSession->Close();
        delete m_pSession;
    }
    m_pSession = NULL;
}

CString CWebGrab::GetErrorMessage()
{
 return m_pSession->GetErrorMessage();
}

void CWebGrab::SetTimeOut(DWORD timeOut)
{
 m_timeOut = timeOut;
}

double CWebGrab::GetRate()
{
 return m_transferRate;
}

void CWebGrab::SetProxyServer(LPCSTR server)
{
 m_Proxy = server;
}

void CWebGrab::SetProxyPort(UINT port)
{
 m_Port = port;
}

void CWebGrab::SetUseProxy(bool use)
{
 m_useProxy = use;
}

void CWebGrab::SetProxy(LPCSTR proxy, WORD port, bool useProxy )
{
 SetProxyServer(proxy);
 SetProxyPort(port);
 SetUseProxy(useProxy);
}

SHORT CWebGrab::GetErrorCode()
{
 return (!m_ErrorMessage.IsEmpty()); //just for now say…
}

BOOL CWebGrab::GetFile(LPCTSTR szURL, CString& strBuffer,
                       LPCTSTR szAgentName /*=NULL*/, CWnd* pWnd /*=NULL*/)
{
  //  TRACE1("URL is %s\n", szURL);
 m_rawHeaders ="";
 m_infoStatusCode=0;
 strBuffer.Empty();

    if (!m_pSession && !Initialise(szAgentName, pWnd))
        return FALSE;

    if (pWnd)
        m_pSession->SetStatusWnd(pWnd);

    //m_pSession->SetStatus("Downloading file…");

    DWORD dwCount = 0;
    CHttpFile* pFile = NULL;
    try
    {
        pFile = (CHttpFile*) m_pSession->OpenURL(szURL, 1,
                                                 INTERNET_FLAG_TRANSFER_BINARY
                                                 //| INTERNET_OPEN_FLAG_USE_EXISTING_CONNECT |
                                                 //| INTERNET_FLAG_DONT_CACHE
                                                 //| INTERNET_FLAG_RELOAD
                                                 );
   
  
 }
    catch (CInternetException* e)
    {
        TCHAR   szCause[255];
        e->GetErrorMessage(szCause, 255);
        m_pSession->SetStatus(szCause);
        // e->ReportError();
        e->Delete();
        delete pFile;
        pFile = NULL;
        return FALSE;
    }
   
    COleDateTime startTime = COleDateTime::GetCurrentTime();
    LPSTR pBuf = NULL;
    if (pFile)
    {
        pBuf = (LPSTR) ::GlobalAlloc(GMEM_FIXED, BUFFER_SIZE+1);
        if (!pBuf)
        {
            pFile->Close();
            delete pFile;
            return FALSE;
        }

        BYTE buffer[BUFFER_SIZE+1];
        try {
            UINT nRead = 0;
            dwCount = 0;
            do
            {
                nRead = pFile->Read(buffer, BUFFER_SIZE);
                if (nRead > 0)
                {
                    buffer[nRead] = 0;

                    LPTSTR ptr = strBuffer.GetBufferSetLength(dwCount + nRead + 1);
                    memcpy(ptr+dwCount, buffer, nRead);

                    dwCount += nRead;
                    strBuffer.ReleaseBuffer(dwCount+1);

                    COleDateTimeSpan elapsed = COleDateTime::GetCurrentTime() – startTime;
                    double dSecs = elapsed.GetTotalSeconds();
                    if (dSecs > 0.0)
     {
                        m_transferRate = (double)dwCount / 1024.0 / dSecs;
      m_pSession->SetStatus("Read %d bytes (%0.1f Kb/s)",
                                             dwCount, m_transferRate );
      
     }
     else
     {
                        m_pSession->SetStatus("Read %d bytes", dwCount);
      m_transferRate = dwCount;
     }
                }
            }
            while (nRead > 0);
        }
        catch (CFileException *e)
        {
            TCHAR   szCause[255];
            e->GetErrorMessage(szCause, 255);
   m_ErrorMessage = szCause;
            m_pSession->SetStatus(szCause);
            //e->ReportError();
            e->Delete();
            delete pFile;
            ::GlobalFree(pBuf); // mem leak fix by Niek Albers
            return FALSE;
        }
        pFile->QueryInfoStatusCode(m_infoStatusCode);      
  pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS ,m_rawHeaders);
        pFile->Close();
   ::GlobalFree(pBuf); // mem leak fix by Niek Albers
        delete pFile;
    }

    m_pSession->SetStatus("");

    return TRUE;
}

DWORD CWebGrab::GetPageStatusCode()
{
 return m_infoStatusCode;
}

CString CWebGrab::GetRawHeaders()
{
 return m_rawHeaders;
}

/////////////////////////////////////////////////////////////////////////////
// CWebGrabSession

CWebGrabSession::CWebGrabSession(LPCTSTR szAgentName)
                : CInternetSession(szAgentName) // , 1, INTERNET_OPEN_TYPE_PRECONFIG,
{
    CommonConstruct();
}

CWebGrabSession::CWebGrabSession(LPCTSTR szAgentName, CWnd* pStatusWnd)
                : CInternetSession(szAgentName) //, 1, INTERNET_OPEN_TYPE_PRECONFIG,
                //                  NULL, NULL, INTERNET_FLAG_ASYNC)
{
    CommonConstruct();
    m_pStatusWnd = pStatusWnd;
}

CWebGrabSession::~CWebGrabSession()
{
}

void CWebGrabSession::CommonConstruct()
{
    m_pStatusWnd = NULL;
    try {
        EnableStatusCallback(TRUE);
    }
    catch (…)
    {}
}

// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CWebGrabSession, CInternetSession)
 //{{AFX_MSG_MAP(CWebGrabSession)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0

/////////////////////////////////////////////////////////////////////////////
// CWebGrabSession member functions

void CWebGrabSession::OnStatusCallback(DWORD dwContext,
                                       DWORD dwInternetStatus,
                                       LPVOID lpvStatusInformation,
                                       DWORD dwStatusInformationLength)
{
 UNUSED_ALWAYS(dwContext);

    // Status callbacks need thread-state protection.
    AFX_MANAGE_STATE( AfxGetAppModuleState( ) );

    CString str;

 //TRACE1("Internet context=%d: %d\n", dwContext);

 switch (dwInternetStatus)
 {
 case INTERNET_STATUS_RESOLVING_NAME:
  str.Format("Resolving name for %s", lpvStatusInformation);
  break;

 case INTERNET_STATUS_NAME_RESOLVED:
  str.Format("Resolved name for %s", lpvStatusInformation);
  break;

 case INTERNET_STATUS_HANDLE_CREATED:
  //str.Format("Handle %8.8X created", hInternet);
  break;

 case INTERNET_STATUS_CONNECTING_TO_SERVER:
  {
  //sockaddr* pSockAddr = (sockaddr*) lpvStatusInformation;
  str.Format("Connecting to socket address "); //, pSockAddr->sa_data);
  }
  break;

 case INTERNET_STATUS_REQUEST_SENT:
  str.Format("Request sent");
  break;

 case INTERNET_STATUS_SENDING_REQUEST:
  str.Format("Sending request…");
  break;

 case INTERNET_STATUS_CONNECTED_TO_SERVER:
  str.Format("Connected to socket address");
  break;

 case INTERNET_STATUS_RECEIVING_RESPONSE:
        return;
  str.Format("Receiving response…");
  break;

 case INTERNET_STATUS_RESPONSE_RECEIVED:
  str.Format("Response received");
  break;

 case INTERNET_STATUS_CLOSING_CONNECTION:
  str.Format("Closing the connection to the server");
  break;

 case INTERNET_STATUS_CONNECTION_CLOSED:
  str.Format("Connection to the server closed");
  break;

 case INTERNET_STATUS_HANDLE_CLOSING:
        return;
  str.Format("Handle closed");
  break;

 case INTERNET_STATUS_REQUEST_COMPLETE:
        // See the CInternetSession constructor for details on INTERNET_FLAG_ASYNC.
        // The lpvStatusInformation parameter points at an INTERNET_ASYNC_RESULT
        // structure, and dwStatusInformationLength contains the final completion
        // status of the asynchronous function. If this is ERROR_INTERNET_EXTENDED_ERROR,
        // the application can retrieve the server error information by using the
        // Win32 function InternetGetLastResponseInfo. See the ActiveX SDK for more
        // information about this function.
  if (dwStatusInformationLength == sizeof(INTERNET_ASYNC_RESULT))
  {
   INTERNET_ASYNC_RESULT* pResult = (INTERNET_ASYNC_RESULT*) lpvStatusInformation;
   str.Format("Request complete, dwResult = %8.8X, dwError = %8.8X",
            pResult->dwResult, pResult->dwError);
  }
  else
   str.Format("Request complete");
  break;

 case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
 case INTERNET_STATUS_REDIRECT:
 default:
  str.Format("Unknown status: %d", dwInternetStatus);
  break;
 }

    SetStatus(str);

    TRACE("CWebGrabSession::OnStatusCallback: %s\n",str);
}

void CWebGrabSession::SetStatus(LPCTSTR fmt, …)
{
    va_list args;
    TCHAR buffer[512];

    va_start(args, fmt);
    _vstprintf(buffer, fmt, args);
    va_end(args);

    TRACE1("CWebGrabSession::SetStatus: %s\n", buffer);
 errorMessage = (CString) buffer;
    if (m_pStatusWnd)
    {
        m_pStatusWnd->SetWindowText(buffer);
        m_pStatusWnd->RedrawWindow();
    }
}

CString CWebGrabSession::GetErrorMessage()
{
 return errorMessage;
}

文章标题:一个对Winsock 完成端口模型封装的类
原 作 者:不详
原 出 处:不详
发 布 者:loose_went
发布类型:转载
发布日期:2004-08-16
今日浏览:10
总 浏 览:3333
下载本文所附源代码



源代码说明: 
在WINDOWS下进行网络服务端程序开发,毫无疑问,Winsock 完成端口模型是最高效的。Winsock的完成端口模型借助Widnows的重叠IO和完成端口来实现,完成端口模型懂了之后是比较简单的,但是要想掌握Winsock完成端口模型,需要对WINDOWS下的线程、线程同步,Winsock API以及WINDOWS IO机制有一定的了解。如果不了解,推荐几本书:《Inside Windows 2000,《WINDOWS核心编程》,《WIN32多线程程序设计》、《WINDOWS网络编程技术》。在去年,我在C语言下用完成端口模型写了一个WEBSERVER,前些天,我决定用C++重写这个WEBSERVER,给这个WEBSERVER增加了一些功能,并改进完成端口操作方法,比如采用AcceptEx来代替accept和使用LOOKASIDE LIST来管理内存,使得WEBSERVER的性能有了比较大的提高。

在重写的开始,我决定把完成端口模型封装成一个比较通用的C++类,针对各种网络服务端程序的开发,只要简单地继承这个类,改写其中两个虚拟函数就能满足各种需要。到昨天为止,WEBSERVER重写完毕,我就写了这篇文章对完成端口模型做一个总结,并介绍一下我的这个类。

DEMO就是一个ECHOSERVER,记得使用Release模式编译。

================================================================================

/*++

Copyright (c) 2004

模块名:

     iomodel.h

模块描述:

     Winsock 完成端口类头文件

作者:

     PPP elssann@hotmail.com

开发环境:
   
     Visual C++ 6.0, Windows 2000.
    
修订记录:

     创建于: 2004.1.16

最后修改日期:
      2004.1.23


–*/

#ifndef      _IOMODEL_H
#define      _IOMODEL_H

//
//Head files
//
#include <winsock2.h>
#include <mswsock.h>


/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

#ifdef __cplusplus
extern "C" {
#endif

       
#define    BUFFER_SIZE           4096
#define    MAXTHREAD_COUNT       8

#define    PORT                  8080
#define    LOCALADDRESS          "172.29.90.96"

#define    IO_READ_COMPLETION    100
#define    IO_WRITE_COMPLETION   200
#define    IO_ACCEPT_COMPLETION  300


//
//自定义枚举数据类型,用来标识套接字IO动作类型
//
typedef enum _IO_OPERATION
{
        IoAccept, //AcceptEx/accept
  IoRead,   //WSARecv/recv/ReadFile
  IoWrite,   //WSASend/send/WriteFile
  IoEnd
}IO_OPERATION, *PIO_OPERATION;

//
//自定义结构,即“完成键”(单句柄数据)
//
typedef struct _PER_HANDLE_CONTEXT
{
 SOCKET                     IoSocket;

 _PER_HANDLE_CONTEXT*       pNext;
}PER_HANDLE_CONTEXT, *PPER_HANDLE_CONTEXT;


//
//单IO数据,扩展的WSAOVERLAPPED
//
typedef struct _PER_IO_CONTEXT
{
 WSAOVERLAPPED              ol;
 char                       szBuffer[BUFFER_SIZE];
 WSABUF                     wsaBuffer;
 SOCKET                     sClient;

 unsigned int               unId;

 IO_OPERATION               IoOperation;

 _PER_IO_CONTEXT*           pNext;
}PER_IO_CONTEXT, *PPER_IO_CONTEXT;

//
// global var
//

static  GUID g_GUIDAcceptEx = WSAID_ACCEPTEX;
static  GUID g_GUIDTransmitFile = WSAID_TRANSMITFILE;

DWORD __stdcall   CompletionRoutine(LPVOID);


//
//完成端口模型类
//


class CompletionPortModel
{
public:
 CompletionPortModel();
 ~CompletionPortModel();

 BOOL                Init();
 BOOL                ThreadLoop();
 BOOL                AllocEventMessage();
 BOOL                PostAcceptEx();
 
 virtual BOOL        HandleData(
         PPER_IO_CONTEXT lpPerIoContext,
            int nFlags
         );
 virtual BOOL        DataAction(
            PPER_IO_CONTEXT lpPerIoContext,
            PPER_HANDLE_CONTEXT lpNewperHandletext
            );
 
 void                InsertNode(PPER_IO_CONTEXT pNode, PPER_HANDLE_CONTEXT pHandleNode);
 void                ReleaseNode(PPER_IO_CONTEXT pNode);
 void                InsertToLookaside(PPER_IO_CONTEXT lpIoNode, PPER_HANDLE_CONTEXT lpHandleNode);

 PPER_IO_CONTEXT     GetIoFromLookaside();
 PPER_HANDLE_CONTEXT GetHandleFromLookaside();


 


 HANDLE                        m_hCOP;
 SOCKET                        m_ListenSocket;
 
 CRITICAL_SECTION              m_ListCriSection;
 CRITICAL_SECTION              m_HandleCriSection;
 CRITICAL_SECTION              m_IoCriSection;

 LPFN_TRANSMITFILE             lpTransmitFile;

 volatile PPER_IO_CONTEXT      m_lpIoLookasideLists;
 volatile PPER_HANDLE_CONTEXT  m_lpHandleLOOKasideLists;
 
protected:
 BOOL                InitWinsock();
 BOOL                BindAndListenSocket();
 BOOL                InitLinkListHead();
 void                CloseThreadHandle();
 void                GetAddressAndPort();

 
 UINT                uPort;
 char                szAddress[20];
 
 HANDLE                        m_hThreadArray[MAXTHREAD_COUNT];
 HANDLE                        m_hEvent;
 
 volatile LONG                 m_lAcceptExCounter;
 volatile PPER_IO_CONTEXT      m_lpConnectionListHead;

 LPFN_ACCEPTEX                 lpAcceptEx;

private:

};


#ifdef __cplusplus
}
#endif

#endif  //_IOMODEL_H

================================================================================

/*++

Copyright (c) 2004

模块名:

     iomodel.cpp

模块描述:

     Winsock 完成端口类实现文件

作者:

     PPP elssann@hotmail.com

开发环境:
   
     Visual C++ 6.0, Windows 2000.
    
修订记录:

     创建于: 2004.1.16

最后修改日期:
      2004.1.23


–*/

#include <iostream.h>
#include <winsock2.h>
#include <mswsock.h>
#include "iomodel.h"


CompletionPortModel::CompletionPortModel()
/*++

函数描述:
    构造函数,初始化线程句柄数组,初始化AcceptEx()调用的计数。初始化临界段代码变量。

Arguments:
     无。

Return Value:
     无。

–*/

{
 for (int i=0; i< MAXTHREAD_COUNT; i++)
 {
  m_hThreadArray[i] = INVALID_HANDLE_VALUE;
 }

 m_lAcceptExCounter = 0;

 InitializeCriticalSection(&m_ListCriSection);
 InitializeCriticalSection(&m_HandleCriSection);
 InitializeCriticalSection(&m_IoCriSection);

 m_lpHandleLOOKasideLists = NULL;
 m_lpIoLookasideLists = NULL;

#ifndef _DEBUG
 GetAddressAndPort();
#endif
}//end of CompletionPortModel()

CompletionPortModel::~CompletionPortModel()
/*++

函数描述:
    析构函数,释放链表所有结点。

Arguments:
     无。

Return Value:

–*/
{
 PPER_IO_CONTEXT lpIoNode;

 while (m_lpConnectionListHead->pNext)
 {
  lpIoNode = m_lpConnectionListHead->pNext;
  m_lpConnectionListHead->pNext = lpIoNode->pNext;
  closesocket(lpIoNode->sClient);
  HeapFree(GetProcessHeap(), 0, lpIoNode);
 }

 while(NULL != m_lpIoLookasideLists)
 {
  lpIoNode = m_lpIoLookasideLists;
  m_lpIoLookasideLists = m_lpIoLookasideLists->pNext;
  HeapFree(GetProcessHeap(), 0, lpIoNode);
 }

 PPER_HANDLE_CONTEXT lpHandleNode;
 while(NULL != m_lpHandleLOOKasideLists)
 {
  lpHandleNode = m_lpHandleLOOKasideLists;
  m_lpHandleLOOKasideLists = m_lpHandleLOOKasideLists->pNext;
  HeapFree(GetProcessHeap(), 0, lpHandleNode);
 }

 DeleteCriticalSection(&m_ListCriSection);
 DeleteCriticalSection(&m_HandleCriSection);
 DeleteCriticalSection(&m_IoCriSection);
 
}//end of ~CompletionPortModel()


BOOL CompletionPortModel::Init()
/*++

函数描述:
    初始化,创建完成端口、创建完成端口线程,并调用类成员函数InitWinsock初始化Winsock、
建立一个监听套接字m_ListenSocket,并将此套接字同完成端口关联起来,获取AcceptEx指针。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。

–*/
{
    BOOL bSuccess = InitLinkListHead();
 
 if (FALSE == bSuccess)
 {
  return FALSE;
 }
 
 m_hCOP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
 if (NULL == m_hCOP)
 {
  cout << "CreateIoCompletionPort() failed: " << GetLastError() << endl;

  return FALSE;
 }

 //
 //取得系统中CPU的数目,创建和CPU数目相等的线程,如果事先估计到完成端口处理线程会堵塞,
 //可以考虑创建 SysInfo.dwNumberOfProcessors*2个线程。一般在单处理器上创建和CPU数目相等
 //的线程就可以了
 //
 SYSTEM_INFO SysInfo;
 GetSystemInfo(&SysInfo);
 if (MAXTHREAD_COUNT < SysInfo.dwNumberOfProcessors)
 {
  SysInfo.dwNumberOfProcessors = MAXTHREAD_COUNT;
 }

 for (int i=0; i<(int)SysInfo.dwNumberOfProcessors; i++)
 {
  m_hThreadArray[i] = CreateThread(NULL, 0, CompletionRoutine, (LPVOID)this, 0, NULL);
  if (NULL == m_hThreadArray[i])
  {
   while (i>0)
   {
    CloseHandle(m_hThreadArray[i-1]);
    m_hThreadArray[i-1] = INVALID_HANDLE_VALUE;
    i–;
   }//end of while

   cout << "CreateThread() failed: " << GetLastError() << endl;
   CloseHandle(m_hCOP);
   HeapFree(GetProcessHeap(), 0, m_lpConnectionListHead);
   
   return FALSE;
  }
 }//end of for

 //
 //调用InitWinsock函数初始化Winsock、建立一个监听套接字m_ListenSocket,
 //并将此套接字同完成端口关联起来,获取AcceptEx指针。
 //
 bSuccess = InitWinsock();
 if (!bSuccess)
 {
  //
  //给完成端口线程发送消息,指示线程退出。
  //
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  CloseThreadHandle();
  CloseHandle(m_hCOP);
  HeapFree(GetProcessHeap(), 0, m_lpConnectionListHead); 

  return FALSE;
 }

 //
 //调用BindAndListenSocket()绑定套接字并将套接字置于监听状态
 //
 bSuccess = BindAndListenSocket(); 
 if (!bSuccess)
 {
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  CloseThreadHandle();
  CloseHandle(m_hCOP);
  HeapFree(GetProcessHeap(), 0, m_lpConnectionListHead);  
  
  return FALSE;
 }

 return TRUE; 
}//end of Init()


void CompletionPortModel::CloseThreadHandle()
/*++

函数描述:
    对每一个创建的线程调用CloseHandle()。

Arguments:
     无。

Return Value:
     无。

–*/
{
 for (int i=0; i< MAXTHREAD_COUNT; i++)
 {
  if (INVALID_HANDLE_VALUE != m_hThreadArray[i])
  {
   CloseHandle(m_hThreadArray[i]);
   m_hThreadArray[i] = INVALID_HANDLE_VALUE;
  }
 }//end of for
 
 return;
}//end of CloseThreadHandle()


BOOL CompletionPortModel::InitWinsock()
/*++

函数描述:
    初始化Winsock,创建一个监听套接字,获取AcceptEx函数指针,为监听套接字分配一个单句柄
 数据,并将监听套接字与完成端口hCOP关联。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。

–*/
{
 WSADATA wsd;
 int nResult = WSAStartup(MAKEWORD(2,2), &wsd);
 if (0 != nResult)
 {
  cout << "WSAStartup() failed" << endl;
  
  return FALSE;
 }

 m_ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP,
          NULL, 0, WSA_FLAG_OVERLAPPED);
    if (INVALID_SOCKET == m_ListenSocket)
    {
  cout << "WSASocket() failed: " << WSAGetLastError() << endl;
        WSACleanup();
       
        return FALSE;
    }
 
 
 DWORD dwResult;

 //
 //获取微软SOCKET扩展函数指针
 //
 nResult = WSAIoctl(
      m_ListenSocket,
      SIO_GET_EXTENSION_FUNCTION_POINTER,
      &g_GUIDAcceptEx,
      sizeof(g_GUIDAcceptEx),
      &lpAcceptEx,
      sizeof(lpAcceptEx),
        &dwResult,
      NULL,
      NULL
      );

 if (SOCKET_ERROR == nResult)
 {
  cout << "Get AcceptEx failed: " << WSAGetLastError() << endl;
  closesocket(m_ListenSocket);
        WSACleanup();

  return FALSE;
 }

 nResult = WSAIoctl( 
      m_ListenSocket,
      SIO_GET_EXTENSION_FUNCTION_POINTER,
      &g_GUIDTransmitFile,
      sizeof(g_GUIDTransmitFile),
      &lpTransmitFile,
      sizeof(lpTransmitFile),
      &dwResult,
      NULL,
      NULL
      );
 
 if (SOCKET_ERROR == nResult)
 {
  cout << "Get TransmitFile failed: " << WSAGetLastError() << endl;
  closesocket(m_ListenSocket);
        WSACleanup();
  
  return FALSE;
 }


 //
 //为监听套接字分配一个单句柄数据
 //
 PPER_HANDLE_CONTEXT lpListenHandleContext = (PPER_HANDLE_CONTEXT)HeapAlloc(
                    GetProcessHeap(), HEAP_ZERO_MEMORY,
                    sizeof(PER_HANDLE_CONTEXT)
                      );
 if (NULL == lpListenHandleContext)
 {
  closesocket(m_ListenSocket);
        WSACleanup();

  cout << "HeapAlloc() failed " << endl;


  return FALSE;
 }

 lpListenHandleContext->IoSocket = m_ListenSocket;
 lpListenHandleContext->pNext = NULL;

 //
 //将监听套接字m_ListenSocket和已经建立的完成端口关联起来
 //
 HANDLE hrc = CreateIoCompletionPort(
          (HANDLE)m_ListenSocket,
          m_hCOP,
          (ULONG_PTR)lpListenHandleContext,
          0
          );
 if (NULL == hrc)
 {
  closesocket(m_ListenSocket);
  HeapFree(GetProcessHeap(), 0, lpListenHandleContext);
  WSACleanup();

  cout << "CreateIoCompletionPort failed: " << GetLastError() << endl;
  
  return FALSE;
 }

 return TRUE;
}//end of InitWinsock()


BOOL CompletionPortModel::BindAndListenSocket()
/*++

函数描述:
    private函数,供Init调用。
 将监听套接字m_ListenSocket绑定到本地IP地址,并置于监听模式。


Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。

–*/
{
    SOCKADDR_IN InternetAddr;
    InternetAddr.sin_family = AF_INET;

#ifdef _DEBUG
    InternetAddr.sin_addr.s_addr = inet_addr(LOCALADDRESS);
    InternetAddr.sin_port = htons(PORT);  
#else
    InternetAddr.sin_addr.s_addr = inet_addr(szAddress);
    InternetAddr.sin_port = htons(uPort);    
#endif 
   
    int nResult = bind(m_ListenSocket, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr));
    if (SOCKET_ERROR == nResult)
    {
        WSACleanup();
  closesocket(m_ListenSocket);
  
  cout << "bind() failed: " << WSAGetLastError() << endl;
       
        return FALSE;
    } 

 nResult = listen(m_ListenSocket, 20);
    if (SOCKET_ERROR == nResult)
    {
        WSACleanup();
  closesocket(m_ListenSocket);

  cout << "listen() failed: " << WSAGetLastError() << endl;
       
        return FALSE;
    }  

 return TRUE;
}//end of BindAndListenSocket()


DWORD __stdcall CompletionRoutine(LPVOID Param)
/*++

函数描述:
    完成端口处理线程,循环调用GetQueuedCompletionStatus来获取IO操作结果。

Arguments:

Return Value:
     线程退出代码。

–*/
{
 CompletionPortModel* pThis = (CompletionPortModel*)Param;
 DWORD dwNumberBytes;
 PPER_HANDLE_CONTEXT lpHandleContext = NULL;
 LPWSAOVERLAPPED lpOverlapped = NULL;
 int nResult;
 BOOL bSuccess;

 while (TRUE)
 {
  bSuccess = GetQueuedCompletionStatus(
           pThis->m_hCOP,
           &dwNumberBytes,
           (PULONG_PTR )&lpHandleContext,
           &lpOverlapped,
           INFINITE
           );


  if (FALSE == bSuccess)
  {

#ifndef _DEBUG
   cout << "GetQueuedCompletionStatus() failed: " << GetLastError() << endl;
#endif

   continue;
  }
  if (NULL == lpHandleContext)
  {
   //
   //PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了。
   //
   return 0;
  }

  PPER_IO_CONTEXT lpPerIoContext = (PPER_IO_CONTEXT)lpOverlapped;

#ifdef _DEBUG
  cout << "recv buffer data: " << lpPerIoContext->szBuffer << endl;  
#endif
  
  if(IoAccept != lpPerIoContext->IoOperation)
  {
   if((!bSuccess) || (bSuccess && (0 == dwNumberBytes)))
   {
    closesocket(lpPerIoContext->sClient);
    lpPerIoContext->pNext = NULL;
    pThis->InsertToLookaside(lpPerIoContext, NULL);
    lpHandleContext->pNext = NULL;
    pThis->InsertToLookaside(NULL, lpHandleContext);
    
    continue;
   }
  }

  HANDLE hResult;
  PPER_HANDLE_CONTEXT lpNewperHandleContext;

  switch(lpPerIoContext->IoOperation)
  {
  case IoAccept :
   if (dwNumberBytes)
   {
    //
    //第一次连接成功并且收到了数据,将这个结点从链表中解除
    //
    EnterCriticalSection(&pThis->m_ListCriSection);
    pThis->ReleaseNode(lpPerIoContext);
    LeaveCriticalSection(&pThis->m_ListCriSection);
   }
   nResult = setsockopt(
        lpPerIoContext->sClient,
        SOL_SOCKET,
        SO_UPDATE_ACCEPT_CONTEXT,
        (char *)&pThis->m_ListenSocket,
        sizeof(pThis->m_ListenSocket)
        );
   if(SOCKET_ERROR == nResult)
   {
    cout << "SO_UPDATE_ACCEPT_CONTEXT failed to update accept socket" << endl;
    closesocket(lpPerIoContext->sClient); 
    lpPerIoContext->pNext = NULL;
    pThis->InsertToLookaside(lpPerIoContext, NULL);
    
    continue;
   }

   
   lpNewperHandleContext = pThis->GetHandleFromLookaside();
   if (NULL == lpNewperHandleContext)
   {
    lpNewperHandleContext = (PPER_HANDLE_CONTEXT)HeapAlloc(
     GetProcessHeap(),
     HEAP_ZERO_MEMORY,
     sizeof(PER_HANDLE_CONTEXT)
     );
    if (NULL == lpNewperHandleContext)
    {
     cout << "HeapAlloc() for lpNewperHandlecontext failed" << endl;
     
     closesocket(lpPerIoContext->sClient);
     lpPerIoContext->pNext = NULL;
     pThis->InsertToLookaside(lpPerIoContext, NULL);
     
     continue;
    }    
   }

   lpNewperHandleContext->IoSocket = lpPerIoContext->sClient;
   lpNewperHandleContext->pNext = NULL;
   
   //
   //将新建立的套接字关联到完成端口
   //
   hResult = CreateIoCompletionPort(
           (HANDLE)lpPerIoContext->sClient,\
           pThis->m_hCOP,
           (DWORD_PTR)lpNewperHandleContext,
           0
           );
   if (NULL == hResult)
   {
    cout << "CreateIoCompletionPort() failed: " << GetLastError();

    closesocket(lpPerIoContext->sClient);
    lpPerIoContext->pNext = NULL;
    lpNewperHandleContext->pNext = NULL;
    pThis->InsertToLookaside(lpPerIoContext, NULL);
    pThis->InsertToLookaside(NULL, lpNewperHandleContext);
    
    continue;
   }

   if (dwNumberBytes)
   {
    //
    //分析处理数据。
    //
    pThis->HandleData(lpPerIoContext, IO_READ_COMPLETION);
    bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
    if (FALSE == bSuccess)
    {
     continue;
    }
   }

   //
   //如果连接成功但是没有收到数据
   //
   else
   {
    pThis->HandleData(lpPerIoContext, IO_ACCEPT_COMPLETION);
    bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
    if (FALSE == bSuccess)
    {
     continue;
    }
   }
   break;//end of case IoAccept
   
  case IoRead:
   pThis->HandleData(lpPerIoContext, IO_READ_COMPLETION);
   bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
   if (FALSE == bSuccess)
   {
    continue;
   }

   break;//end of case IoRead

  case IoWrite:
   pThis->HandleData(lpPerIoContext, IO_WRITE_COMPLETION);
   bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
   if (FALSE == bSuccess)
   {
    continue;
   } 

   break;

  default:
   continue;
   break;
  }
 }

 return 0;

}//end of CompletionRoutine()

BOOL CompletionPortModel::PostAcceptEx()
/*++

Fucntion Description:

 连续发出10个AcceptEx调用。

Arguments:

Return Value:

 函数调用成功返回TRUE,失败返回FALSE。
 
–*/
{
  while (m_lAcceptExCounter < 10)
  {
   SOCKET AcceptSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, \
          NULL, 0, WSA_FLAG_OVERLAPPED);  
   if (INVALID_SOCKET == AcceptSocket)
   {
    cout << "WSASocket failed " << endl;
    
    return FALSE;
   }

   PPER_IO_CONTEXT lpAcceptExIoContext = GetIoFromLookaside();
   if (NULL == lpAcceptExIoContext)
   {
    lpAcceptExIoContext = (PPER_IO_CONTEXT)HeapAlloc(\
     GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
    if (NULL == lpAcceptExIoContext)
    {
     cout << "HeapAlloc() failed " << endl;
     closesocket(AcceptSocket);
     
     return FALSE;
    }
   }

   ZeroMemory(&(lpAcceptExIoContext->ol), sizeof(lpAcceptExIoContext->ol));
   lpAcceptExIoContext->sClient = AcceptSocket;
   lpAcceptExIoContext->IoOperation = IoAccept;
   lpAcceptExIoContext->pNext = NULL;
   ZeroMemory(lpAcceptExIoContext->szBuffer, BUFFER_SIZE);
   lpAcceptExIoContext->wsaBuffer.buf = lpAcceptExIoContext->szBuffer;
   lpAcceptExIoContext->wsaBuffer.len = BUFFER_SIZE;
   lpAcceptExIoContext->unId = lpAcceptExIoContext->sClient;
   
   DWORD dwBytes;
   BOOL bSuccess = lpAcceptEx(
     m_ListenSocket,
     lpAcceptExIoContext->sClient,
     lpAcceptExIoContext->szBuffer,
     lpAcceptExIoContext->wsaBuffer.len – ((sizeof(SOCKADDR_IN) + 16) * 2),
     sizeof(SOCKADDR_IN) + 16,
     sizeof(SOCKADDR_IN) + 16,
     &dwBytes,
     &(lpAcceptExIoContext->ol));

   if (FALSE == bSuccess)
   {
    int nResult = WSAGetLastError();
    if (nResult != ERROR_IO_PENDING)
    {
     cout << "AcceptEx() failed :" << nResult << endl;
     closesocket(AcceptSocket);
     HeapFree(GetProcessHeap(), 0 , lpAcceptExIoContext);
     
     return FALSE;
    }
    
    InsertNode(lpAcceptExIoContext, NULL); 
    InterlockedExchangeAdd(&m_lAcceptExCounter, 1);
   }
  }

  InterlockedExchangeAdd(&m_lAcceptExCounter, -10);

 return TRUE;
}//end of PostAccetExRoutine()

void CompletionPortModel::InsertNode(PPER_IO_CONTEXT pNode, PPER_HANDLE_CONTEXT pHandleNode)
/*++

Fucntion Description:

 根据参数类型将传递进来结点插入到相应的链表头。

Arguments:

    pNode       -  要插入链表中的结点
 pHandleNode -  要插入链表中的结点
 
Return Value:

 无.

–*/
{
 if (NULL != pNode)
 {  
  EnterCriticalSection(&m_ListCriSection);
  pNode->pNext = m_lpConnectionListHead->pNext;
  m_lpConnectionListHead->pNext = pNode;
  LeaveCriticalSection(&m_ListCriSection);
 }

 return;
}//end of InsertNode


BOOL CompletionPortModel::ThreadLoop()
/*++

Fucntion Description:
 
   主线程循环,用WaitForSigleObject等待m_hEvent,已经发出的AcceptEx()调用耗尽,FD_ACCEPT
事件将被触发,WaitForSigleObject成功返回,然后调用PostAcceptEx()来新发出10个AcceptEx()调用。
WaitForSigleObject每次等待10秒,超时返回后,对系统中已经建立成功了的并且还没有收发过数据的
SOCKET连接进行检测,如果某个连接已经建立了30秒,并且还没收发过数据,则强制关闭。

Arguments:
    
   无。

Return Value:
     
   函数调用成功返回TRUE,调用失败返回FALSE;
    
–*/
{
 int nOptval;
 int nOptlen;
 int nResult;
 DWORD dwResult;
 int nCounter = 0;

#ifdef _DEBUG
 int nTimeOut = 0;
#endif

 cout << "Server is running………." << nCounter << " times" << endl; 
 
 while (TRUE)
 {  
  dwResult = WaitForSingleObject(m_hEvent, 10000);
 
  if (WAIT_FAILED == dwResult)
  {
   PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
   cout << "WSAWaitForMultipleEvents() failed: " << WSAGetLastError() << endl;

   return FALSE;
  }
  
  if (WAIT_TIMEOUT == dwResult)
  { 
   nCounter++;
   cout << "Server is running………." << nCounter << " times" << endl;
   
#ifdef _DEBUG
   nTimeOut++;
   cout << nTimeOut << "*******TIME_OUT********" << nTimeOut << endl;
#endif
   
   PPER_IO_CONTEXT lpCurentNode = m_lpConnectionListHead->pNext;
   PPER_IO_CONTEXT lpPreNode = m_lpConnectionListHead;
   PPER_IO_CONTEXT lpTempNode; 
   
   while (NULL != lpCurentNode)
   { 
    EnterCriticalSection(&m_ListCriSection);
    nOptlen = sizeof(nOptval);
    nResult = getsockopt(
     lpCurentNode->sClient,
     SOL_SOCKET,
     SO_CONNECT_TIME,
     (char*)&nOptval,
     &nOptlen
     );
#ifdef _DEBUG
    cout << "nOptval = " << nOptval << endl;
#endif _DEBUG
    
    if (SOCKET_ERROR == nResult)
    {
     cout << "SO_CONNECT_TIME failed: " << WSAGetLastError() << endl;
     lpPreNode = lpCurentNode;
     lpCurentNode = lpCurentNode->pNext;
     LeaveCriticalSection(&m_ListCriSection);
     
     continue;
    }
    if ((nOptval!=0xFFFFFFFF) && (nOptval>30))
    {
     lpPreNode->pNext = lpCurentNode->pNext;
     lpTempNode = lpCurentNode;
     lpCurentNode = lpCurentNode->pNext;
     closesocket(lpTempNode->sClient);
     lpTempNode->pNext = NULL;
     InsertToLookaside(lpTempNode, NULL);
    }
    else
    {
     lpPreNode = lpCurentNode;
     lpCurentNode = lpCurentNode->pNext;
    }
    LeaveCriticalSection(&m_ListCriSection);
   }
  }
  else
  {
   if (WAIT_TIMEOUT != dwResult)
   {
    if (FALSE == PostAcceptEx())
    {
     PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
     
     return FALSE;
    }
   }
  }
 }

 return TRUE;
}//end of CheckConnectTime

void CompletionPortModel::ReleaseNode(PPER_IO_CONTEXT pNode)
/*++

Fucntion Description:

     将参数中传递的结点从链表中解除,但不释放结点。以便不让ThreadLoop函数对其进行超时检测。
此函数在完成端口线程里收发数据成功后调用。

Arguments:
    
  要从链表中释放的结点。

Return Value:

     无。
    
–*/
{
 PPER_IO_CONTEXT pTempNode = m_lpConnectionListHead->pNext;
 PPER_IO_CONTEXT pPreNode =m_lpConnectionListHead;
 PPER_IO_CONTEXT pDeleteNode;
 
 while (NULL != pTempNode)
 {
  if (pNode->unId == pTempNode->unId)
  {  
   pPreNode->pNext = pTempNode->pNext;
   pDeleteNode = pTempNode;
   pTempNode = pTempNode->pNext;
   
   return;
  }
  else
  { 
   pPreNode = pTempNode;
   pTempNode = pTempNode->pNext;
  }
 }

 return;
}//end of RealeseNode


BOOL CompletionPortModel::HandleData(PPER_IO_CONTEXT lpPerIoContext, int nFlags)
/*++

Fucntion Description:

      根据传进来的nFlags参数对lpPerIoContext进行设置,并指示下一步IO操作。

Arguments:
    
      lpPerIoContext – 调用GetQueueCompletionStatus函数得到的上一次IO操作的结果(扩展的
                      WSAOVERLAPPED结构)。
      nFlags         – 指明已经完成上一次IO的操作类型。

Return Value:

      函数调用成功返回TRUE,失败返回FALSE。
    
–*/
{
 //
 //nFlags == IO_READ_COMPLETION表示完成的上一次IO操作是WSARecv。
 //
 if (IO_READ_COMPLETION == nFlags)
 {
  //
  //完成了WSARecv,接下来需要调用WSASend把刚接收到的数据发送回去,把
  //lpPerIoContext->ContinueAction = ContinueWrite;
  //
  lpPerIoContext->IoOperation = IoWrite;
  ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
  
  //
  //接收到的数据在lpPerIoContext->wsaBuffer.buf里,可以调用
  //自定义函数对数据自行处理,本例中,简单的将数据再发送回去
  //
  strcpy(lpPerIoContext->szBuffer, lpPerIoContext->wsaBuffer.buf);
  lpPerIoContext->wsaBuffer.buf = lpPerIoContext->szBuffer;
  lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
  
  return TRUE;
 }

 if (IO_WRITE_COMPLETION == nFlags)
 {
  //
  //上一次IO操作WSASend数据发送完成,将后续操作标志设置为关闭
  //如果不需要关闭而是要继续发送,将lpPerIoContext->IoOperation设置为
  //IoWrite,如果要继续接收,将lpPerIoContext->IoOperation设置为
  //IoRead,并初始化好BUFFER,本例中,设置关闭
  //
  lpPerIoContext->IoOperation = IoEnd;

  return TRUE;
 }
 if (IO_ACCEPT_COMPLETION == nFlags)
 {
  //
  //刚建立了一个连接,并且没有收发数据,,,,
  //
  lpPerIoContext->IoOperation = IoRead;
  ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
  ZeroMemory(lpPerIoContext->szBuffer, BUFFER_SIZE);
  lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
  lpPerIoContext->wsaBuffer.buf = lpPerIoContext->szBuffer;

  return TRUE;
 }
 
 
 return FALSE;
}// end of HandleData()


BOOL CompletionPortModel::InitLinkListHead()
/*++

Fucntion Description:

     初始化链表头指针。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。
    
–*/
{
 m_lpConnectionListHead = (PPER_IO_CONTEXT)HeapAlloc(GetProcessHeap(), \
  HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
 
 if (NULL == m_lpConnectionListHead)
 {
  cout << "HeapAlloc() failed " << endl;
  
  return FALSE;
 }
 m_lpConnectionListHead->pNext = NULL;
 
 return TRUE;
}// end of InitLinkListHead()

BOOL CompletionPortModel::AllocEventMessage()
/*++

Fucntion Description:

     将FD_ACCEPT事件注册到m_hEvent,这样当可用AcceptEx调用被耗尽的时候,就会触发FD_ACCEPT
  事件,然后ThreadLoop里的WaitForSingleObject就会成功返回,导致PostAcceptEx被调用。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。
    
–*/
{
 m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 if (NULL == m_hEvent)
 {
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  cout << "CreateEvent() failed: " << GetLastError() << endl;

  return FALSE;
 }
 
 int nResult = WSAEventSelect(m_ListenSocket, m_hEvent, FD_ACCEPT);
 if (SOCKET_ERROR == nResult)
 {
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  CloseHandle(m_hEvent);

  cout << "WSAEventSeclet() failed: " << WSAGetLastError() << endl;
  
  return FALSE;
 }

 return TRUE;
}//end of AllocEventMessage()


BOOL CompletionPortModel::DataAction(PPER_IO_CONTEXT lpPerIoContext, PPER_HANDLE_CONTEXT lpNewperHandleContext)
/*++

Fucntion Description:

     根据参数lpPerIoContext的成员IoOperation的值来进行下一步IO操作。

Arguments:
    
  lpPerIoContext        – 将随WSASend或者WSARecv一起投递的扩展WSAOVERLAPPED结构。
  lpNewperHandleContext – AcceptEx调用成功后给新套接字分配的“单句柄数据”。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。
    
–*/
{
 int nResult;
 DWORD dwIosize = 0;
 DWORD dwFlags =0;
 if (IoWrite == lpPerIoContext->IoOperation)
 {
  nResult = WSASend(lpPerIoContext->sClient,
     &(lpPerIoContext->wsaBuffer),
     1,
     &dwIosize,
     0,
     &(lpPerIoContext->ol),
     NULL
     );
  if((SOCKET_ERROR==nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
  {
   cout << "WSASend() failed: " << WSAGetLastError() << endl;
   
   closesocket(lpPerIoContext->sClient);
   lpPerIoContext->pNext = NULL;
   lpNewperHandleContext->pNext = NULL;
   InsertToLookaside(lpPerIoContext, NULL);
   InsertToLookaside(NULL, lpNewperHandleContext);
   
   return FALSE;
  }
 }
 
 if (IoRead == lpPerIoContext->IoOperation)
 {
  nResult = WSARecv(lpPerIoContext->sClient,
     &(lpPerIoContext->wsaBuffer),
     1,
     &dwIosize,
     &dwFlags,
     &(lpPerIoContext->ol),
     NULL
     );
     
  if((SOCKET_ERROR==nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
  {
   cout << "WSARecv() failed: " << WSAGetLastError() << endl;
    
   closesocket(lpPerIoContext->sClient);
   lpNewperHandleContext->pNext = NULL;
   lpPerIoContext->pNext = NULL;
   InsertToLookaside(lpPerIoContext, NULL);
   InsertToLookaside(NULL, lpNewperHandleContext);
     
   return FALSE;
  }
   
 }
    
 if (IoEnd == lpPerIoContext->IoOperation)
 {
  closesocket(lpPerIoContext->sClient);
  lpNewperHandleContext->pNext = NULL;
  InsertToLookaside(NULL, lpNewperHandleContext);
  lpPerIoContext->pNext = NULL;
  InsertToLookaside(lpPerIoContext, NULL);
 }

 return TRUE;
}// end of DataAction()


void CompletionPortModel::GetAddressAndPort()
/*++

Fucntion Description:

     由类构造函数调用的函数,用来输入服务器要绑定的本地IP地址和端口。

Arguments:
    
  无。

Return Value:
    
 无。  
    
–*/
{
 cout << "\nPlease input a port: ";
 cin >> uPort;
 cout << "\nPlease input localaddress:";
 cin >> szAddress;

 system("cls");

 return;
}// end of GetAddressAdnPort


void CompletionPortModel::InsertToLookaside(PPER_IO_CONTEXT lpIoNode, PPER_HANDLE_CONTEXT lpHandleNode)
/*++

Fucntion Description:

     给旁视列表的链表中插入一个空闲的结点。

Arguments:
    
  lpIoNode     – 要插入的结点,类型为PPER_IO_CONTEXT。
  lpHandleNode – 要插入的结点,类型为PPER_HANDLE_CONTEXT。

Return Value:
    
 无。  
    
–*/
{
 if (NULL != lpIoNode)
 {
  if (NULL == m_lpIoLookasideLists)
  {
   m_lpIoLookasideLists = lpIoNode;
   
   return;
  }
  lpIoNode->pNext = m_lpIoLookasideLists->pNext;
  m_lpIoLookasideLists->pNext = lpIoNode;
  
  return;
 }

 if (NULL != lpHandleNode)
 {
  if (NULL == m_lpHandleLOOKasideLists)
  {
   m_lpHandleLOOKasideLists = lpHandleNode;
   
   return;
  }
  lpHandleNode->pNext = m_lpHandleLOOKasideLists->pNext;
  m_lpHandleLOOKasideLists->pNext = lpHandleNode;
  
  return;
 }

 return;
}


PPER_IO_CONTEXT CompletionPortModel::GetIoFromLookaside()
/*++

Fucntion Description:

     从旁视列表中解除一个结点并将其返回。

Arguments:
    
  无。

Return Value:
    
 返回一个PPER_IO_CONTEXT类型的结点。  
    
–*/
{
 if (NULL == m_lpIoLookasideLists)
 {
  return NULL;
 }
 EnterCriticalSection(&m_IoCriSection);
 PPER_IO_CONTEXT lpReturnNode = m_lpIoLookasideLists;
 m_lpIoLookasideLists = m_lpIoLookasideLists->pNext;
 LeaveCriticalSection(&m_IoCriSection);

 return lpReturnNode;
}

PPER_HANDLE_CONTEXT CompletionPortModel::GetHandleFromLookaside()
/*++

Fucntion Description:

     从旁视列表中解除一个结点并将其返回。

Arguments:
    
  无。

Return Value:
    
 返回一个PPER_HANDLE_CONTEXT类型的结点。  
    
–*/
{
 if (NULL == m_lpHandleLOOKasideLists)
 {
  return NULL;
 }
 EnterCriticalSection(&m_HandleCriSection);
 PPER_HANDLE_CONTEXT lpReturnNode = m_lpHandleLOOKasideLists;
 m_lpHandleLOOKasideLists = m_lpHandleLOOKasideLists->pNext;
 LeaveCriticalSection(&m_HandleCriSection);
 
 return lpReturnNode;
}

================================================================================
/*++

Copyright (c) 2004

模块名:

     main.cpp

模块描述:

     主线程文件

作者:

     PPP elssann@hotmail.com

开发环境:
   
     Visual C++ 6.0, Windows 2000.
    
修订记录:

     创建于: 2004.1.16

最后修改日期:
      2004.1.23


–*/

#include "iomodel.h"
#include <winsock2.h>
#include <windows.h>
#include <iostream.h>

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


void main()
{
 CompletionPortModel p;
 p.Init();
 p.AllocEventMessage();
 if (FALSE == p.PostAcceptEx())
 {
  return;
 }
 p.ThreadLoop();

 return;
}