VC命名管道服务类
代码
// MyPipeServer.h: interface for the CMyPipeServer class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MYPIPESERVER_H__2DC67C68_21FA_4725_8328_31AE97DB3944__INCLUDED_)
#define AFX_MYPIPESERVER_H__2DC67C68_21FA_4725_8328_31AE97DB3944__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <windows.h>
#include <afxtempl.h>
#include "http://www.cnblogs.com/Comm/MyPipeData.h"
#define BUFFERSIZE 4096
typedef struct _PIPESTRUCT_
{
HANDLE hPipeHandle;
HANDLE hNeedWriteEvent;
HANDLE hOverEvent;
char pReadBuf[BUFFERSIZE];
char pWriteBuf[BUFFERSIZE];
BOOL bIsConnected;
public:
BOOL bIsWriteThreadOver;
BOOL bIsReadThreadOver;
HANDLE hDisconnectPipeEvent;
}PIPESTRUCT,*PPIPESTRUCT;
typedef CList<PPIPESTRUCT,PPIPESTRUCT> PPIPESTRUCTLIST;
typedef void (CALLBACK* PIPENOTIFYPROC)(LPVOID, PIPEDATA*);
class CMyService;
class CMyPipeServer
{
public:
HANDLE m_hNeedWrite;
HANDLE m_hConnectionClosed;
UINT m_uConnectedClientCount;
void WriteData(PBYTE strData,UINT nLen);
static unsigned int __stdcall PipeThread(LPVOID lParam);
static unsigned int __stdcall WriteThread(LPVOID lParam);
bool InitPipe(LPCSTR strPipeName , PIPENOTIFYPROC pNotifyProc, CMyService* pService, DWORD dwMaxInstance = 1);
CMyPipeServer();
virtual ~CMyPipeServer();
private:
HANDLE m_hWaitWrite;
void ClosePipe();
HANDLE m_hThreadOverEvent;
PPIPESTRUCTLIST m_pPipeStructList;
public:
HANDLE m_CurrentWriteHandle;
DWORD m_dwMaxInstance;
bool m_bTimeToKill;
char m_strPipeName[255];
protected:
PIPENOTIFYPROC m_pNotifyProc;
CMyService* m_pService;
};
#endif // !defined(AFX_MYPIPESERVER_H__2DC67C68_21FA_4725_8328_31AE97DB3944__INCLUDED_)
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_MYPIPESERVER_H__2DC67C68_21FA_4725_8328_31AE97DB3944__INCLUDED_)
#define AFX_MYPIPESERVER_H__2DC67C68_21FA_4725_8328_31AE97DB3944__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <windows.h>
#include <afxtempl.h>
#include "http://www.cnblogs.com/Comm/MyPipeData.h"
#define BUFFERSIZE 4096
typedef struct _PIPESTRUCT_
{
HANDLE hPipeHandle;
HANDLE hNeedWriteEvent;
HANDLE hOverEvent;
char pReadBuf[BUFFERSIZE];
char pWriteBuf[BUFFERSIZE];
BOOL bIsConnected;
public:
BOOL bIsWriteThreadOver;
BOOL bIsReadThreadOver;
HANDLE hDisconnectPipeEvent;
}PIPESTRUCT,*PPIPESTRUCT;
typedef CList<PPIPESTRUCT,PPIPESTRUCT> PPIPESTRUCTLIST;
typedef void (CALLBACK* PIPENOTIFYPROC)(LPVOID, PIPEDATA*);
class CMyService;
class CMyPipeServer
{
public:
HANDLE m_hNeedWrite;
HANDLE m_hConnectionClosed;
UINT m_uConnectedClientCount;
void WriteData(PBYTE strData,UINT nLen);
static unsigned int __stdcall PipeThread(LPVOID lParam);
static unsigned int __stdcall WriteThread(LPVOID lParam);
bool InitPipe(LPCSTR strPipeName , PIPENOTIFYPROC pNotifyProc, CMyService* pService, DWORD dwMaxInstance = 1);
CMyPipeServer();
virtual ~CMyPipeServer();
private:
HANDLE m_hWaitWrite;
void ClosePipe();
HANDLE m_hThreadOverEvent;
PPIPESTRUCTLIST m_pPipeStructList;
public:
HANDLE m_CurrentWriteHandle;
DWORD m_dwMaxInstance;
bool m_bTimeToKill;
char m_strPipeName[255];
protected:
PIPENOTIFYPROC m_pNotifyProc;
CMyService* m_pService;
};
#endif // !defined(AFX_MYPIPESERVER_H__2DC67C68_21FA_4725_8328_31AE97DB3944__INCLUDED_)
CPP文件:
代码
// MyPipeServer.cpp: implementation of the CMyPipeServer class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FileUploaderServer.h"
#include "MyPipeServer.h"
#include <process.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMyPipeServer::CMyPipeServer()
{
m_bTimeToKill = false;
m_hThreadOverEvent = CreateEvent(NULL,TRUE,FALSE,NULL);//初始化线程结束信号,并指定手动复位
m_hWaitWrite = CreateEvent(NULL,TRUE,FALSE,NULL);//初始化线程结束信号,并指定手动复位
m_hNeedWrite = CreateEvent(NULL,TRUE,FALSE,NULL);
m_dwMaxInstance = 1;
}
CMyPipeServer::~CMyPipeServer()
{
ClosePipe();
}
//初始化命名管道
//strPipeName:管道名
//dwMaxInstance:最大连接数(默认为1)
bool CMyPipeServer::InitPipe(LPCSTR strPipeName, PIPENOTIFYPROC pNotifyProc,CMyService* pService,DWORD dwMaxInstance)
{
m_pNotifyProc = pNotifyProc;
m_pService = pService;
//m_pMyLog->AddLog("初始化命名管道");
int len = strlen(strPipeName) + 11;
memset(m_strPipeName, 0 , 255);
strcpy(m_strPipeName,"\\\\.\\pipe\\");
strcat(m_strPipeName,strPipeName);
m_dwMaxInstance = dwMaxInstance<1?1:dwMaxInstance;
m_uConnectedClientCount = 0;
char buf[100];
UINT dwThreadId;
HANDLE hThread;
for(DWORD i=0;i<m_dwMaxInstance;i++)
{
//启动管道线程
hThread =(HANDLE)_beginthreadex(NULL,0,PipeThread,(void*)this,0,&dwThreadId);
if(hThread)
{
CloseHandle(hThread);
memset(buf,0,100);
sprintf(buf,"成功启动管道线程,线程ID为 %u",dwThreadId);
//m_pMyLog->AddLog(buf);
}
}
return true;
}
//等待连接线程
unsigned int CMyPipeServer::PipeThread(LPVOID lParam)
{
//m_pMyLog->AddLog("%u:进入等待连接线程",::GetCurrentThreadId());
CMyPipeServer* pThis=reinterpret_cast<CMyPipeServer*>(lParam);
HANDLE hThisPipe;
PIPEDATA* pPipeData = new PIPEDATA;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
//创建命名管道
hThisPipe = CreateNamedPipe(pThis->m_strPipeName,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,//全双工,使用重叠
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
pThis->m_dwMaxInstance,
BUFFERSIZE,//OutBufferSize
BUFFERSIZE,//InBufferSize
10,//DefaultTimeOut 10 ms
&sa);
if (hThisPipe == INVALID_HANDLE_VALUE)
{
//m_pMyLog->AddLog("%u:初始化命名管道失败",::GetCurrentThreadId());
return false;
}
PPIPESTRUCT pPipeStruct=new PIPESTRUCT;
memset(pPipeStruct,0,sizeof(PIPESTRUCT));
pPipeStruct->bIsConnected = FALSE;
pPipeStruct->hNeedWriteEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
pPipeStruct->hOverEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
pPipeStruct->hDisconnectPipeEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
pPipeStruct->hPipeHandle = hThisPipe;
pPipeStruct->bIsReadThreadOver = FALSE;
pPipeStruct->bIsWriteThreadOver = TRUE;
//启动管道写线程
UINT dwThreadId;
HANDLE hThread =(HANDLE) _beginthreadex(NULL,0,WriteThread,(void*)pPipeStruct,0,&dwThreadId);
if(hThread)
{
CloseHandle(hThread);
//m_pMyLog->AddLog(buf);
}
pThis->m_pPipeStructList.AddTail(pPipeStruct);
//m_pMyLog->AddLog("%u:初始化命名管道成功",::GetCurrentThreadId());
BOOL bConnected;
OVERLAPPED Overlapped;
DWORD dwError;
DWORD dwResult;
HANDLE hHasDataRead;
hHasDataRead = CreateEvent(NULL,TRUE,FALSE,NULL);
HANDLE hConnectEvent;
hConnectEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE HandleVector[2];
HandleVector[0] = pThis->m_hThreadOverEvent;
HandleVector[1] = hConnectEvent;
HANDLE HandleVector_Read[3];
HandleVector_Read[0] = pThis->m_hThreadOverEvent;
HandleVector_Read[1] = hHasDataRead;
HandleVector_Read[2] = pPipeStruct->hDisconnectPipeEvent;
BOOL bNeedExit = FALSE;
while(!pThis->m_bTimeToKill)
{
ResetEvent(pPipeStruct->hDisconnectPipeEvent);
pPipeStruct->bIsConnected = FALSE;
memset(&Overlapped,0,sizeof(OVERLAPPED));
Overlapped.hEvent = hConnectEvent;
//Overlapped.hEvent为手工复位
//m_pMyLog->AddLog("%u:管道线程等待连接",::GetCurrentThreadId());
bConnected = FALSE;
bConnected = ConnectNamedPipe(hThisPipe, &Overlapped);//异步,非阻塞模式,立即返回
dwResult = WaitForMultipleObjectsEx(2,HandleVector,FALSE,INFINITE,FALSE);
//等待线程结束信号 和 客户连接成功信号
if(dwResult == WAIT_OBJECT_0)
{
break;
}
else if(dwResult == WAIT_OBJECT_0+1)
{
bConnected = TRUE;
//m_pMyLog->AddLog("%u:客户端连接成功",::GetCurrentThreadId());
pThis->m_uConnectedClientCount++ ;
}
dwError = GetLastError();
bConnected = bConnected ?bConnected : (dwError == ERROR_PIPE_CONNECTED);
if(!bConnected)
{
//m_pMyLog->AddLog("%u:bConnected=FALSE;LastErrorCode=%u",::GetCurrentThreadId(),dwError);
}
else
{
//m_pMyLog->AddLog("bConnected=TRUE;LastErrorCode=%u",dwError);
}
pPipeStruct->bIsConnected = TRUE;
OVERLAPPED Overlapped_Read;
while(!pThis->m_bTimeToKill)
{
memset(&Overlapped_Read,0,sizeof(OVERLAPPED));
Overlapped_Read.hEvent = hHasDataRead;
memset(pPipeStruct->pReadBuf,0,BUFFERSIZE);
////m_pMyLog->AddLog("%u:等待读取客户端的数据",::GetCurrentThreadId());
DWORD dwBytesRead;
BOOL bSuccess = ReadFile(hThisPipe,pPipeStruct->pReadBuf,BUFFERSIZE,&dwBytesRead,&Overlapped_Read);
//ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。
//而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
//如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,
//线程应该调用GetLastError函数分析返回的结果。
//例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,
//而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成
dwResult = WaitForMultipleObjectsEx(3,HandleVector_Read,FALSE,1000,FALSE);
//如果要求线程结束
if(dwResult == WAIT_OBJECT_0)
{
//m_pMyLog->AddLog("%u:dwResult == WAIT_OBJECT_0 等待线程结束。",::GetCurrentThreadId());
bNeedExit = TRUE;
break;
}
else if(dwResult == WAIT_OBJECT_0 + 1 )
{
//m_pMyLog->AddLog("%u:读到客户端数据:",::GetCurrentThreadId());
//memset(pPipeStruct->pWriteBuf,0,BUFFERSIZE);
//strcpy(pPipeStruct->pWriteBuf,pPipeStruct->pReadBuf);
////m_pMyLog->AddLog(pThis->writeBuffer);
//ResetEvent(hHasDataRead);
//SetEvent(pPipeStruct->hNeedWriteEvent);
memset(pPipeData,0,sizeof(PIPEDATA));
CopyMemory(pPipeData,pPipeStruct->pReadBuf,sizeof(PIPEDATA));
pThis->m_pNotifyProc(pThis->m_pService,pPipeData);
}
else if(dwResult == WAIT_OBJECT_0 + 2)
{
//客户端关闭
SetEvent(pPipeStruct->hDisconnectPipeEvent);
pPipeStruct->bIsConnected = FALSE;
break;
}
else if(dwResult == WAIT_TIMEOUT)
{
dwError = GetLastError();
if(dwError == ERROR_IO_PENDING)
{
::CancelIo(hThisPipe);
}
else if(dwError == ERROR_PIPE_NOT_CONNECTED)
{
//m_pMyLog->AddLog("%u:dwResult == WAIT_OBJECT_0 +1 客户端关闭。线程重新等待连接。",::GetCurrentThreadId());
pPipeStruct->bIsConnected = FALSE;
SetEvent(pPipeStruct->hDisconnectPipeEvent);
break;
}
}//end else if
}//end while(!pThis->m_bTimeToKill)
pThis->m_uConnectedClientCount--;
FlushFileBuffers(hThisPipe);
DisconnectNamedPipe(hThisPipe);
//m_pMyLog->AddLog("%u:FlushFileBuffers:",::GetCurrentThreadId());
//m_pMyLog->AddLog("%u:DisconnectNamedPipe:",::GetCurrentThreadId());
if(bNeedExit)
{
break;
}
}
//m_pMyLog->AddLog("%u:等待线程结束退出",::GetCurrentThreadId());
delete pPipeData;
CloseHandle(hThisPipe);
pPipeStruct->bIsReadThreadOver = TRUE;
return 0;
}
//写线程 使用信号量pThis->m_hNeedWrite控制写
//要写的数据 保存在pThis->writeBuffer,大小4096字节
unsigned int CMyPipeServer::WriteThread(LPVOID lParam)
{
PPIPESTRUCT pPipeStruct=reinterpret_cast<PPIPESTRUCT>(lParam);
pPipeStruct->bIsWriteThreadOver = FALSE;
DWORD dwBytesToWrite;
DWORD dwBytesWrite;
DWORD dwResult;
DWORD dwError;
PBYTE writeBuffer = new BYTE[BUFFERSIZE];
OVERLAPPED Overlapped;
HANDLE hWriteResult = CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE HandleVector[2];
HANDLE HandleVector_WaitWrite[3];
HandleVector[0] = pPipeStruct->hOverEvent;
HandleVector[1] = pPipeStruct->hNeedWriteEvent;
HandleVector_WaitWrite[0] = pPipeStruct->hOverEvent;
HandleVector_WaitWrite[1] = hWriteResult;
HandleVector_WaitWrite[2] = pPipeStruct->hDisconnectPipeEvent;
//m_pMyLog->AddLog("%u:进入管道写线程",::GetCurrentThreadId());
while(1)
{
dwResult = WaitForMultipleObjectsEx(2,HandleVector,FALSE,INFINITE,FALSE);
if(dwResult == WAIT_OBJECT_0)//pPipeStruct->hOverEvent;
break;
else if(WAIT_OBJECT_0 + 1 == dwResult)//pPipeStruct->hNeedWriteEvent;
{
//m_pMyLog->AddLog("%u:准备写数据",::GetCurrentThreadId());
memset(writeBuffer,0,BUFFERSIZE);
CopyMemory(writeBuffer,pPipeStruct->pWriteBuf,BUFFERSIZE);
dwBytesToWrite =BUFFERSIZE;
ResetEvent(hWriteResult);
memset(&Overlapped,0,sizeof(OVERLAPPED));
Overlapped.Offset = 0;
Overlapped.hEvent = hWriteResult;
dwBytesWrite = 0;
if(pPipeStruct->hPipeHandle != INVALID_HANDLE_VALUE && pPipeStruct->bIsConnected)
{
//m_pMyLog->AddLog("%u:开始写数据",::GetCurrentThreadId());
////m_pMyLog->AddLog(writeBuffer);
BOOL bSuccess = WriteFile(pPipeStruct->hPipeHandle,writeBuffer,dwBytesToWrite,&dwBytesWrite,&Overlapped);
//ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。
//而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
//如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,
//线程应该调用GetLastError函数分析返回的结果。
//例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,
//而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成
if(bSuccess)
{
//m_pMyLog->AddLog("%u:等待写操作完成.bSuccess=TRUE.",::GetCurrentThreadId());
}
else
{
dwError = GetLastError();
if(dwError == ERROR_NO_DATA || dwError == ERROR_PIPE_NOT_CONNECTED)
{
//m_pMyLog->AddLog("%u:客户端关闭了管道。",::GetCurrentThreadId());
DisconnectNamedPipe(pPipeStruct->hPipeHandle);
pPipeStruct->bIsConnected = FALSE;
SetEvent(pPipeStruct->hDisconnectPipeEvent);
ResetEvent(pPipeStruct->hNeedWriteEvent);
continue;
}
else if(dwError == ERROR_INVALID_HANDLE)
{
//m_pMyLog->AddLog("%u:管道已经关闭。",::GetCurrentThreadId());
ResetEvent(pPipeStruct->hNeedWriteEvent);
continue;
}
else
{
//m_pMyLog->AddLog("%u:未知错误:%u",::GetCurrentThreadId(),dwError);
}
}
dwResult = WaitForMultipleObjectsEx(3,HandleVector_WaitWrite,FALSE,INFINITE,FALSE);
if(dwResult == WAIT_OBJECT_0)//pPipeStruct->hOverEvent;
break;
if(dwResult == WAIT_OBJECT_0 +1)//hWriteResult
{
//m_pMyLog->AddLog("%u:dwResult == WAIT_OBJECT_0 写入数据成功,文件大小:%u",::GetCurrentThreadId(),dwBytesWrite);
}
else if(dwResult == WAIT_OBJECT_0 +2)//pPipeStruct->hDisconnectPipeEvent;
{
//m_pMyLog->AddLog("%u:管道已经关闭。",::GetCurrentThreadId());
ResetEvent(pPipeStruct->hNeedWriteEvent);
}
else
{
dwError = GetLastError();
switch(dwError)
{
case ERROR_HANDLE_EOF:
//m_pMyLog->AddLog("%u:GetLastError() = ERROR_HANDLE_EOF。",::GetCurrentThreadId());
break;
case ERROR_IO_PENDING:
//m_pMyLog->AddLog("%u:GetLastError() = ERROR_IO_PENDING",::GetCurrentThreadId());
::CancelIo(pPipeStruct->hPipeHandle);
break;
//default:
//m_pMyLog->AddLog("%u:未知错误GetLastError()=%u",::GetCurrentThreadId(),dwError);
}
}
}
ResetEvent(pPipeStruct->hNeedWriteEvent);
}
//else
////m_pMyLog->AddLog("%u:没有数据需要写入",::GetCurrentThreadId());
}
delete writeBuffer;
//m_pMyLog->AddLog("%u:写线程结束退出.",::GetCurrentThreadId());
pPipeStruct->bIsWriteThreadOver = TRUE;
return 0;
}
void CMyPipeServer::ClosePipe()
{
m_bTimeToKill = true;
SetEvent(m_hThreadOverEvent);//发出线程结果信号
while(!m_pPipeStructList.IsEmpty())
{
PPIPESTRUCT hPipeStruct = m_pPipeStructList.RemoveTail();
if(hPipeStruct->bIsConnected)
DisconnectNamedPipe(hPipeStruct->hPipeHandle);
SetEvent(hPipeStruct->hOverEvent);
while(!hPipeStruct->bIsReadThreadOver || !hPipeStruct->bIsWriteThreadOver)
{
Sleep(100);
}
}
}
void CMyPipeServer::WriteData(PBYTE pData,UINT nLen)
{
POSITION pos = m_pPipeStructList.GetHeadPosition();
//向所有管道客户端写数据
while(pos)
{
PPIPESTRUCT hPipeStruct = m_pPipeStructList.GetNext(pos);
CopyMemory(hPipeStruct->pWriteBuf,pData,nLen);
SetEvent(hPipeStruct->hNeedWriteEvent);
}
}
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FileUploaderServer.h"
#include "MyPipeServer.h"
#include <process.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMyPipeServer::CMyPipeServer()
{
m_bTimeToKill = false;
m_hThreadOverEvent = CreateEvent(NULL,TRUE,FALSE,NULL);//初始化线程结束信号,并指定手动复位
m_hWaitWrite = CreateEvent(NULL,TRUE,FALSE,NULL);//初始化线程结束信号,并指定手动复位
m_hNeedWrite = CreateEvent(NULL,TRUE,FALSE,NULL);
m_dwMaxInstance = 1;
}
CMyPipeServer::~CMyPipeServer()
{
ClosePipe();
}
//初始化命名管道
//strPipeName:管道名
//dwMaxInstance:最大连接数(默认为1)
bool CMyPipeServer::InitPipe(LPCSTR strPipeName, PIPENOTIFYPROC pNotifyProc,CMyService* pService,DWORD dwMaxInstance)
{
m_pNotifyProc = pNotifyProc;
m_pService = pService;
//m_pMyLog->AddLog("初始化命名管道");
int len = strlen(strPipeName) + 11;
memset(m_strPipeName, 0 , 255);
strcpy(m_strPipeName,"\\\\.\\pipe\\");
strcat(m_strPipeName,strPipeName);
m_dwMaxInstance = dwMaxInstance<1?1:dwMaxInstance;
m_uConnectedClientCount = 0;
char buf[100];
UINT dwThreadId;
HANDLE hThread;
for(DWORD i=0;i<m_dwMaxInstance;i++)
{
//启动管道线程
hThread =(HANDLE)_beginthreadex(NULL,0,PipeThread,(void*)this,0,&dwThreadId);
if(hThread)
{
CloseHandle(hThread);
memset(buf,0,100);
sprintf(buf,"成功启动管道线程,线程ID为 %u",dwThreadId);
//m_pMyLog->AddLog(buf);
}
}
return true;
}
//等待连接线程
unsigned int CMyPipeServer::PipeThread(LPVOID lParam)
{
//m_pMyLog->AddLog("%u:进入等待连接线程",::GetCurrentThreadId());
CMyPipeServer* pThis=reinterpret_cast<CMyPipeServer*>(lParam);
HANDLE hThisPipe;
PIPEDATA* pPipeData = new PIPEDATA;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
//创建命名管道
hThisPipe = CreateNamedPipe(pThis->m_strPipeName,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,//全双工,使用重叠
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
pThis->m_dwMaxInstance,
BUFFERSIZE,//OutBufferSize
BUFFERSIZE,//InBufferSize
10,//DefaultTimeOut 10 ms
&sa);
if (hThisPipe == INVALID_HANDLE_VALUE)
{
//m_pMyLog->AddLog("%u:初始化命名管道失败",::GetCurrentThreadId());
return false;
}
PPIPESTRUCT pPipeStruct=new PIPESTRUCT;
memset(pPipeStruct,0,sizeof(PIPESTRUCT));
pPipeStruct->bIsConnected = FALSE;
pPipeStruct->hNeedWriteEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
pPipeStruct->hOverEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
pPipeStruct->hDisconnectPipeEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
pPipeStruct->hPipeHandle = hThisPipe;
pPipeStruct->bIsReadThreadOver = FALSE;
pPipeStruct->bIsWriteThreadOver = TRUE;
//启动管道写线程
UINT dwThreadId;
HANDLE hThread =(HANDLE) _beginthreadex(NULL,0,WriteThread,(void*)pPipeStruct,0,&dwThreadId);
if(hThread)
{
CloseHandle(hThread);
//m_pMyLog->AddLog(buf);
}
pThis->m_pPipeStructList.AddTail(pPipeStruct);
//m_pMyLog->AddLog("%u:初始化命名管道成功",::GetCurrentThreadId());
BOOL bConnected;
OVERLAPPED Overlapped;
DWORD dwError;
DWORD dwResult;
HANDLE hHasDataRead;
hHasDataRead = CreateEvent(NULL,TRUE,FALSE,NULL);
HANDLE hConnectEvent;
hConnectEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE HandleVector[2];
HandleVector[0] = pThis->m_hThreadOverEvent;
HandleVector[1] = hConnectEvent;
HANDLE HandleVector_Read[3];
HandleVector_Read[0] = pThis->m_hThreadOverEvent;
HandleVector_Read[1] = hHasDataRead;
HandleVector_Read[2] = pPipeStruct->hDisconnectPipeEvent;
BOOL bNeedExit = FALSE;
while(!pThis->m_bTimeToKill)
{
ResetEvent(pPipeStruct->hDisconnectPipeEvent);
pPipeStruct->bIsConnected = FALSE;
memset(&Overlapped,0,sizeof(OVERLAPPED));
Overlapped.hEvent = hConnectEvent;
//Overlapped.hEvent为手工复位
//m_pMyLog->AddLog("%u:管道线程等待连接",::GetCurrentThreadId());
bConnected = FALSE;
bConnected = ConnectNamedPipe(hThisPipe, &Overlapped);//异步,非阻塞模式,立即返回
dwResult = WaitForMultipleObjectsEx(2,HandleVector,FALSE,INFINITE,FALSE);
//等待线程结束信号 和 客户连接成功信号
if(dwResult == WAIT_OBJECT_0)
{
break;
}
else if(dwResult == WAIT_OBJECT_0+1)
{
bConnected = TRUE;
//m_pMyLog->AddLog("%u:客户端连接成功",::GetCurrentThreadId());
pThis->m_uConnectedClientCount++ ;
}
dwError = GetLastError();
bConnected = bConnected ?bConnected : (dwError == ERROR_PIPE_CONNECTED);
if(!bConnected)
{
//m_pMyLog->AddLog("%u:bConnected=FALSE;LastErrorCode=%u",::GetCurrentThreadId(),dwError);
}
else
{
//m_pMyLog->AddLog("bConnected=TRUE;LastErrorCode=%u",dwError);
}
pPipeStruct->bIsConnected = TRUE;
OVERLAPPED Overlapped_Read;
while(!pThis->m_bTimeToKill)
{
memset(&Overlapped_Read,0,sizeof(OVERLAPPED));
Overlapped_Read.hEvent = hHasDataRead;
memset(pPipeStruct->pReadBuf,0,BUFFERSIZE);
////m_pMyLog->AddLog("%u:等待读取客户端的数据",::GetCurrentThreadId());
DWORD dwBytesRead;
BOOL bSuccess = ReadFile(hThisPipe,pPipeStruct->pReadBuf,BUFFERSIZE,&dwBytesRead,&Overlapped_Read);
//ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。
//而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
//如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,
//线程应该调用GetLastError函数分析返回的结果。
//例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,
//而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成
dwResult = WaitForMultipleObjectsEx(3,HandleVector_Read,FALSE,1000,FALSE);
//如果要求线程结束
if(dwResult == WAIT_OBJECT_0)
{
//m_pMyLog->AddLog("%u:dwResult == WAIT_OBJECT_0 等待线程结束。",::GetCurrentThreadId());
bNeedExit = TRUE;
break;
}
else if(dwResult == WAIT_OBJECT_0 + 1 )
{
//m_pMyLog->AddLog("%u:读到客户端数据:",::GetCurrentThreadId());
//memset(pPipeStruct->pWriteBuf,0,BUFFERSIZE);
//strcpy(pPipeStruct->pWriteBuf,pPipeStruct->pReadBuf);
////m_pMyLog->AddLog(pThis->writeBuffer);
//ResetEvent(hHasDataRead);
//SetEvent(pPipeStruct->hNeedWriteEvent);
memset(pPipeData,0,sizeof(PIPEDATA));
CopyMemory(pPipeData,pPipeStruct->pReadBuf,sizeof(PIPEDATA));
pThis->m_pNotifyProc(pThis->m_pService,pPipeData);
}
else if(dwResult == WAIT_OBJECT_0 + 2)
{
//客户端关闭
SetEvent(pPipeStruct->hDisconnectPipeEvent);
pPipeStruct->bIsConnected = FALSE;
break;
}
else if(dwResult == WAIT_TIMEOUT)
{
dwError = GetLastError();
if(dwError == ERROR_IO_PENDING)
{
::CancelIo(hThisPipe);
}
else if(dwError == ERROR_PIPE_NOT_CONNECTED)
{
//m_pMyLog->AddLog("%u:dwResult == WAIT_OBJECT_0 +1 客户端关闭。线程重新等待连接。",::GetCurrentThreadId());
pPipeStruct->bIsConnected = FALSE;
SetEvent(pPipeStruct->hDisconnectPipeEvent);
break;
}
}//end else if
}//end while(!pThis->m_bTimeToKill)
pThis->m_uConnectedClientCount--;
FlushFileBuffers(hThisPipe);
DisconnectNamedPipe(hThisPipe);
//m_pMyLog->AddLog("%u:FlushFileBuffers:",::GetCurrentThreadId());
//m_pMyLog->AddLog("%u:DisconnectNamedPipe:",::GetCurrentThreadId());
if(bNeedExit)
{
break;
}
}
//m_pMyLog->AddLog("%u:等待线程结束退出",::GetCurrentThreadId());
delete pPipeData;
CloseHandle(hThisPipe);
pPipeStruct->bIsReadThreadOver = TRUE;
return 0;
}
//写线程 使用信号量pThis->m_hNeedWrite控制写
//要写的数据 保存在pThis->writeBuffer,大小4096字节
unsigned int CMyPipeServer::WriteThread(LPVOID lParam)
{
PPIPESTRUCT pPipeStruct=reinterpret_cast<PPIPESTRUCT>(lParam);
pPipeStruct->bIsWriteThreadOver = FALSE;
DWORD dwBytesToWrite;
DWORD dwBytesWrite;
DWORD dwResult;
DWORD dwError;
PBYTE writeBuffer = new BYTE[BUFFERSIZE];
OVERLAPPED Overlapped;
HANDLE hWriteResult = CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLE HandleVector[2];
HANDLE HandleVector_WaitWrite[3];
HandleVector[0] = pPipeStruct->hOverEvent;
HandleVector[1] = pPipeStruct->hNeedWriteEvent;
HandleVector_WaitWrite[0] = pPipeStruct->hOverEvent;
HandleVector_WaitWrite[1] = hWriteResult;
HandleVector_WaitWrite[2] = pPipeStruct->hDisconnectPipeEvent;
//m_pMyLog->AddLog("%u:进入管道写线程",::GetCurrentThreadId());
while(1)
{
dwResult = WaitForMultipleObjectsEx(2,HandleVector,FALSE,INFINITE,FALSE);
if(dwResult == WAIT_OBJECT_0)//pPipeStruct->hOverEvent;
break;
else if(WAIT_OBJECT_0 + 1 == dwResult)//pPipeStruct->hNeedWriteEvent;
{
//m_pMyLog->AddLog("%u:准备写数据",::GetCurrentThreadId());
memset(writeBuffer,0,BUFFERSIZE);
CopyMemory(writeBuffer,pPipeStruct->pWriteBuf,BUFFERSIZE);
dwBytesToWrite =BUFFERSIZE;
ResetEvent(hWriteResult);
memset(&Overlapped,0,sizeof(OVERLAPPED));
Overlapped.Offset = 0;
Overlapped.hEvent = hWriteResult;
dwBytesWrite = 0;
if(pPipeStruct->hPipeHandle != INVALID_HANDLE_VALUE && pPipeStruct->bIsConnected)
{
//m_pMyLog->AddLog("%u:开始写数据",::GetCurrentThreadId());
////m_pMyLog->AddLog(writeBuffer);
BOOL bSuccess = WriteFile(pPipeStruct->hPipeHandle,writeBuffer,dwBytesToWrite,&dwBytesWrite,&Overlapped);
//ReadFile函数只要在串口输入缓冲区中读入指定数量的字符,就算完成操作。
//而WriteFile函数不但要把指定数量的字符拷入到输出缓冲区,而且要等这些字符从串行口送出去后才算完成操作。
//如果操作成功,这两个函数都返回TRUE。需要注意的是,当ReadFile和WriteFile返回FALSE时,不一定就是操作失败,
//线程应该调用GetLastError函数分析返回的结果。
//例如,在重叠操作时如果操作还未完成函数就返回,那么函数就返回FALSE,
//而且GetLastError函数返回ERROR_IO_PENDING。这说明重叠操作还未完成
if(bSuccess)
{
//m_pMyLog->AddLog("%u:等待写操作完成.bSuccess=TRUE.",::GetCurrentThreadId());
}
else
{
dwError = GetLastError();
if(dwError == ERROR_NO_DATA || dwError == ERROR_PIPE_NOT_CONNECTED)
{
//m_pMyLog->AddLog("%u:客户端关闭了管道。",::GetCurrentThreadId());
DisconnectNamedPipe(pPipeStruct->hPipeHandle);
pPipeStruct->bIsConnected = FALSE;
SetEvent(pPipeStruct->hDisconnectPipeEvent);
ResetEvent(pPipeStruct->hNeedWriteEvent);
continue;
}
else if(dwError == ERROR_INVALID_HANDLE)
{
//m_pMyLog->AddLog("%u:管道已经关闭。",::GetCurrentThreadId());
ResetEvent(pPipeStruct->hNeedWriteEvent);
continue;
}
else
{
//m_pMyLog->AddLog("%u:未知错误:%u",::GetCurrentThreadId(),dwError);
}
}
dwResult = WaitForMultipleObjectsEx(3,HandleVector_WaitWrite,FALSE,INFINITE,FALSE);
if(dwResult == WAIT_OBJECT_0)//pPipeStruct->hOverEvent;
break;
if(dwResult == WAIT_OBJECT_0 +1)//hWriteResult
{
//m_pMyLog->AddLog("%u:dwResult == WAIT_OBJECT_0 写入数据成功,文件大小:%u",::GetCurrentThreadId(),dwBytesWrite);
}
else if(dwResult == WAIT_OBJECT_0 +2)//pPipeStruct->hDisconnectPipeEvent;
{
//m_pMyLog->AddLog("%u:管道已经关闭。",::GetCurrentThreadId());
ResetEvent(pPipeStruct->hNeedWriteEvent);
}
else
{
dwError = GetLastError();
switch(dwError)
{
case ERROR_HANDLE_EOF:
//m_pMyLog->AddLog("%u:GetLastError() = ERROR_HANDLE_EOF。",::GetCurrentThreadId());
break;
case ERROR_IO_PENDING:
//m_pMyLog->AddLog("%u:GetLastError() = ERROR_IO_PENDING",::GetCurrentThreadId());
::CancelIo(pPipeStruct->hPipeHandle);
break;
//default:
//m_pMyLog->AddLog("%u:未知错误GetLastError()=%u",::GetCurrentThreadId(),dwError);
}
}
}
ResetEvent(pPipeStruct->hNeedWriteEvent);
}
//else
////m_pMyLog->AddLog("%u:没有数据需要写入",::GetCurrentThreadId());
}
delete writeBuffer;
//m_pMyLog->AddLog("%u:写线程结束退出.",::GetCurrentThreadId());
pPipeStruct->bIsWriteThreadOver = TRUE;
return 0;
}
void CMyPipeServer::ClosePipe()
{
m_bTimeToKill = true;
SetEvent(m_hThreadOverEvent);//发出线程结果信号
while(!m_pPipeStructList.IsEmpty())
{
PPIPESTRUCT hPipeStruct = m_pPipeStructList.RemoveTail();
if(hPipeStruct->bIsConnected)
DisconnectNamedPipe(hPipeStruct->hPipeHandle);
SetEvent(hPipeStruct->hOverEvent);
while(!hPipeStruct->bIsReadThreadOver || !hPipeStruct->bIsWriteThreadOver)
{
Sleep(100);
}
}
}
void CMyPipeServer::WriteData(PBYTE pData,UINT nLen)
{
POSITION pos = m_pPipeStructList.GetHeadPosition();
//向所有管道客户端写数据
while(pos)
{
PPIPESTRUCT hPipeStruct = m_pPipeStructList.GetNext(pos);
CopyMemory(hPipeStruct->pWriteBuf,pData,nLen);
SetEvent(hPipeStruct->hNeedWriteEvent);
}
}
使用示例:
代码
void CMyService::Run()
{
//m_pMyLog = new CMyLog(m_strLogFile);
m_pMyPipeServer.InitPipe(m_szPipeName,PipeNotifyProc,this,3);//初始化管道服务器,最多允许三个客户端进行连接
m_iocpServer.Initialize(NotifyProc,this,10000,999);
m_bIsRunning = TRUE;
while (m_bIsRunning) {
Sleep(5000);
/*memset(pPipeData,0,sizeof(PIPEDATA));
CTime time = CTime::GetCurrentTime();
pPipeData->bIsActive = TRUE;
pPipeData->dtLoginTime.uYear = time.GetYear();
pPipeData->dtLoginTime.uMonth = time.GetMonth();
pPipeData->dtLoginTime.uDay = time.GetDay();
pPipeData->dtLoginTime.uHour = time.GetHour();
pPipeData->dtLoginTime.uMinute = time.GetMinute();
pPipeData->dtLoginTime.uSecond = time.GetSecond();
pPipeData->dwDownSize = 123400;
pPipeData->dwDownSpeed = 2643;
pPipeData->dwID = 5634;
pPipeData->nPort = 2305;
strcpy(pPipeData->szLoginIP , "192.168.18.2");
strcpy(pPipeData->szUserName , "管道测试");
memset(pData,0,sizeof(PIPEDATA));
CopyMemory(pData,pPipeData,sizeof(PIPEDATA));
m_pMyPipeServer.WriteData(pData,sizeof(PIPEDATA));*/
// Update the current state
//m_iState += m_iIncParam;
}
m_bIsRunning = FALSE;
}
void CMyService::PipeNotifyProc(LPVOID lpParam, PIPEDATA* pPipeData)
{
CMyService* pThis = (CMyService*) lpParam;
if(pThis->m_bIsRunning == FALSE)
return;
memset(pThis->pData,0,sizeof(PIPEDATA));
CString sHost;
sHost.Format("%s:%d",pPipeData->szLoginIP,pPipeData->nPort);
if(pPipeData->dwOperationType == 0x0001)
{
ClientContext* pContext = pThis->m_iocpServer.FindClient(sHost);
if(pContext == NULL)
{
strcpy(pPipeData->szLastOrder,"NC_CLIENT_DISCONNECT");
pPipeData->bIsActive = FALSE;
}
else
{
strcpy(pPipeData->szLastOrder,"NC_CLIENT_IDLE");
pPipeData->bIsActive = FALSE;
}
CopyMemory(pThis->pData,pPipeData,sizeof(PIPEDATA));
pThis->m_pMyPipeServer.WriteData(pThis->pData,sizeof(PIPEDATA));
}
}
void CMyService::NotifyProc(LPVOID lpParam, ClientContext* pContext, UINT nCode)
{
CMyService* pThis = (CMyService*) lpParam;
pThis->WritePipeData(pContext , nCode);
}
void CMyService::WritePipeData(ClientContext *pContext , UINT nCode)
{
if(m_bIsRunning == FALSE)
return;
memset(pPipeData,0,sizeof(PIPEDATA));
CTimeSpan ts_w = CTime::GetCurrentTime() - pContext->m_tLastWriteTime;
CTimeSpan ts_r = CTime::GetCurrentTime() - pContext->m_tLastRecievTime;
pPipeData->bIsActive = TRUE;
switch (nCode)
{
case NC_CLIENT_CONNECT:
strcpy(pPipeData->szLastOrder,"NC_CLIENT_CONNECT");
break;
case NC_CLIENT_DISCONNECT:
strcpy(pPipeData->szLastOrder,"NC_CLIENT_DISCONNECT");
pPipeData->bIsActive = FALSE;
break;
case NC_CLIENT_IDLE:
strcpy(pPipeData->szLastOrder,"NC_CLIENT_IDLE");
pPipeData->bIsActive = FALSE;
break;
case NC_TRANSMIT:
strcpy(pPipeData->szLastOrder,pContext->m_szOrder);
break;
case NC_RECEIVE:
strcpy(pPipeData->szLastOrder,pContext->m_szOrder);
break;
}
pPipeData->dtLoginTime.uYear = pContext->m_loginTime.GetYear();
pPipeData->dtLoginTime.uMonth = pContext->m_loginTime.GetMonth();
pPipeData->dtLoginTime.uDay = pContext->m_loginTime.GetDay();
pPipeData->dtLoginTime.uHour = pContext->m_loginTime.GetHour();
pPipeData->dtLoginTime.uMinute = pContext->m_loginTime.GetMinute();
pPipeData->dtLoginTime.uSecond = pContext->m_loginTime.GetSecond();
pPipeData->dwDownSize = pContext->dwDownSize / 1024; //KB
pPipeData->dwUploadSize = pContext->dwUploadSize / 1024; //KB
pPipeData->dwUploadSpeed = pPipeData->dwUploadSize / ts_r.GetTotalSeconds();//上传速度 KB/s
pPipeData->dwDownSpeed = pPipeData->dwDownSize / ts_w.GetTotalSeconds();//下载速度 KB/s
pPipeData->dwID = pContext->dwID;
pPipeData->nPort = pContext->nPort;
strcpy(pPipeData->szLoginIP , pContext->m_IP);
strcpy(pPipeData->szUserName , pContext->szUserName);
memset(pData,0,sizeof(PIPEDATA));
CopyMemory(pData,pPipeData,sizeof(PIPEDATA));
m_pMyPipeServer.WriteData(pData,sizeof(PIPEDATA));
}
{
//m_pMyLog = new CMyLog(m_strLogFile);
m_pMyPipeServer.InitPipe(m_szPipeName,PipeNotifyProc,this,3);//初始化管道服务器,最多允许三个客户端进行连接
m_iocpServer.Initialize(NotifyProc,this,10000,999);
m_bIsRunning = TRUE;
while (m_bIsRunning) {
Sleep(5000);
/*memset(pPipeData,0,sizeof(PIPEDATA));
CTime time = CTime::GetCurrentTime();
pPipeData->bIsActive = TRUE;
pPipeData->dtLoginTime.uYear = time.GetYear();
pPipeData->dtLoginTime.uMonth = time.GetMonth();
pPipeData->dtLoginTime.uDay = time.GetDay();
pPipeData->dtLoginTime.uHour = time.GetHour();
pPipeData->dtLoginTime.uMinute = time.GetMinute();
pPipeData->dtLoginTime.uSecond = time.GetSecond();
pPipeData->dwDownSize = 123400;
pPipeData->dwDownSpeed = 2643;
pPipeData->dwID = 5634;
pPipeData->nPort = 2305;
strcpy(pPipeData->szLoginIP , "192.168.18.2");
strcpy(pPipeData->szUserName , "管道测试");
memset(pData,0,sizeof(PIPEDATA));
CopyMemory(pData,pPipeData,sizeof(PIPEDATA));
m_pMyPipeServer.WriteData(pData,sizeof(PIPEDATA));*/
// Update the current state
//m_iState += m_iIncParam;
}
m_bIsRunning = FALSE;
}
void CMyService::PipeNotifyProc(LPVOID lpParam, PIPEDATA* pPipeData)
{
CMyService* pThis = (CMyService*) lpParam;
if(pThis->m_bIsRunning == FALSE)
return;
memset(pThis->pData,0,sizeof(PIPEDATA));
CString sHost;
sHost.Format("%s:%d",pPipeData->szLoginIP,pPipeData->nPort);
if(pPipeData->dwOperationType == 0x0001)
{
ClientContext* pContext = pThis->m_iocpServer.FindClient(sHost);
if(pContext == NULL)
{
strcpy(pPipeData->szLastOrder,"NC_CLIENT_DISCONNECT");
pPipeData->bIsActive = FALSE;
}
else
{
strcpy(pPipeData->szLastOrder,"NC_CLIENT_IDLE");
pPipeData->bIsActive = FALSE;
}
CopyMemory(pThis->pData,pPipeData,sizeof(PIPEDATA));
pThis->m_pMyPipeServer.WriteData(pThis->pData,sizeof(PIPEDATA));
}
}
void CMyService::NotifyProc(LPVOID lpParam, ClientContext* pContext, UINT nCode)
{
CMyService* pThis = (CMyService*) lpParam;
pThis->WritePipeData(pContext , nCode);
}
void CMyService::WritePipeData(ClientContext *pContext , UINT nCode)
{
if(m_bIsRunning == FALSE)
return;
memset(pPipeData,0,sizeof(PIPEDATA));
CTimeSpan ts_w = CTime::GetCurrentTime() - pContext->m_tLastWriteTime;
CTimeSpan ts_r = CTime::GetCurrentTime() - pContext->m_tLastRecievTime;
pPipeData->bIsActive = TRUE;
switch (nCode)
{
case NC_CLIENT_CONNECT:
strcpy(pPipeData->szLastOrder,"NC_CLIENT_CONNECT");
break;
case NC_CLIENT_DISCONNECT:
strcpy(pPipeData->szLastOrder,"NC_CLIENT_DISCONNECT");
pPipeData->bIsActive = FALSE;
break;
case NC_CLIENT_IDLE:
strcpy(pPipeData->szLastOrder,"NC_CLIENT_IDLE");
pPipeData->bIsActive = FALSE;
break;
case NC_TRANSMIT:
strcpy(pPipeData->szLastOrder,pContext->m_szOrder);
break;
case NC_RECEIVE:
strcpy(pPipeData->szLastOrder,pContext->m_szOrder);
break;
}
pPipeData->dtLoginTime.uYear = pContext->m_loginTime.GetYear();
pPipeData->dtLoginTime.uMonth = pContext->m_loginTime.GetMonth();
pPipeData->dtLoginTime.uDay = pContext->m_loginTime.GetDay();
pPipeData->dtLoginTime.uHour = pContext->m_loginTime.GetHour();
pPipeData->dtLoginTime.uMinute = pContext->m_loginTime.GetMinute();
pPipeData->dtLoginTime.uSecond = pContext->m_loginTime.GetSecond();
pPipeData->dwDownSize = pContext->dwDownSize / 1024; //KB
pPipeData->dwUploadSize = pContext->dwUploadSize / 1024; //KB
pPipeData->dwUploadSpeed = pPipeData->dwUploadSize / ts_r.GetTotalSeconds();//上传速度 KB/s
pPipeData->dwDownSpeed = pPipeData->dwDownSize / ts_w.GetTotalSeconds();//下载速度 KB/s
pPipeData->dwID = pContext->dwID;
pPipeData->nPort = pContext->nPort;
strcpy(pPipeData->szLoginIP , pContext->m_IP);
strcpy(pPipeData->szUserName , pContext->szUserName);
memset(pData,0,sizeof(PIPEDATA));
CopyMemory(pData,pPipeData,sizeof(PIPEDATA));
m_pMyPipeServer.WriteData(pData,sizeof(PIPEDATA));
}