命名管道通讯遇到的问题,希望大家帮助
自己最近写了个使用命名管道进行通讯的类,但是在使用的时候确出现问题,百思不解,现把情况说一下,希望大家给点意见,谢谢。
这个类中我使用三线程模型,对命名管道进行读写。其中SenderThrdFunc用于将等待发送数据链表中的数据写入到命名管道中,但是我在跟踪调试的时候发现,每当程序走到这个函数的WriteFile这一步的时候就一直阻塞了,感觉是写不到管道中而不能返回。但是又可以确定管道是肯定已经连接上的……请大家帮忙看看
代码:
CNamedPipe::CNamedPipe()
{
InitializeCriticalSection(&m_csRecvDataQueue);
InitializeCriticalSection(&m_csSendDataQueue);
m_bIsConnected = FALSE;
//创建三个事件,初始化为非设置状态;
m_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //当对象被消灭时通知线程退出;
m_hSendEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //由程序主线程和发送线程共同维护;
m_hWorkEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //由接收线程和工作线程共同维护;
m_lpParam = NULL;
}
CNamedPipe::~CNamedPipe()
{
DeleteCriticalSection(&m_csRecvDataQueue);
DeleteCriticalSection(&m_csSendDataQueue);
CloseHandle(m_hExitEvent);
CloseHandle(m_hSendEvent);
CloseHandle(m_hWorkEvent);
if (m_hNamedPipe != NULL || m_hNamedPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(m_hNamedPipe);
}
}
//接收数据线程函数;
UINT CNamedPipe::RecvThrdFunc(LPVOID lpParam)
{
CNamedPipe * m_pNamedPipe = (CNamedPipe*)lpParam;
if (m_pNamedPipe->m_bAsServer)
{
//服务器端;
while (TRUE)
{
//等待客户端连接到命名管道(阻塞方式);
if (!ConnectNamedPipe(m_pNamedPipe->m_hNamedPipe, NULL))
{
if (GetLastError() != ERROR_PIPE_CONNECTED)
{
break;
}
}
m_pNamedPipe->m_bIsConnected = TRUE; //服务器和客户端已经成功连接;
char szDataBuffer[PIPE_BUF_SIZE] = {0};
DWORD dwRetLen = 0;
while (ReadFile(m_pNamedPipe->m_hNamedPipe, szDataBuffer,
PIPE_BUF_SIZE, &dwRetLen, NULL) && dwRetLen != 0)
{
//将接收到的数据放到接收数据链表里;
DATA_NODE node;
node.uiBufLength = dwRetLen;
memcpy(node.szBuffer, szDataBuffer, dwRetLen);
//插入链表队列;
::EnterCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
if (m_pNamedPipe->m_lRecvDataQueue.IsEmpty())
{
m_pNamedPipe->m_lRecvDataQueue.AddTail(node);
::LeaveCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
//设置事件,告诉工作线程可以开始工作了;
SetEvent(m_pNamedPipe->m_hWorkEvent);
}
else
{
m_pNamedPipe->m_lRecvDataQueue.AddTail(node);
::LeaveCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
}
}
//连接出错,服务器和客户端连接已经断开;
m_pNamedPipe->m_bIsConnected = FALSE;
//断开与客户端的连接;
DisconnectNamedPipe(m_pNamedPipe->m_hNamedPipe);
//连接出错,服务器和客户端连接已经断开,直接调用回调函数;
m_pNamedPipe->m_pCallbackFunc(NULL, 0, m_pNamedPipe->m_lpParam);
}
}
else
{
char szDataBuffer[PIPE_BUF_SIZE] = {0};
DWORD dwRetLen = 0;
while (ReadFile(m_pNamedPipe->m_hNamedPipe, szDataBuffer, PIPE_BUF_SIZE,
&dwRetLen, NULL) && dwRetLen != 0)
{
//将接收到的数据放到接收数据链表里;
DATA_NODE node;
node.uiBufLength = dwRetLen;
memcpy(node.szBuffer, szDataBuffer, dwRetLen);
//插入链表队列;
::EnterCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
if (m_pNamedPipe->m_lRecvDataQueue.IsEmpty())
{
m_pNamedPipe->m_lRecvDataQueue.AddTail(node);
::LeaveCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
//设置事件,告诉工作线程可以开始工作了;
SetEvent(m_pNamedPipe->m_hWorkEvent);
}
else
{
m_pNamedPipe->m_lRecvDataQueue.AddTail(node);
::LeaveCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
}
}
//连接出错,服务器和客户端连接已经断开;
m_pNamedPipe->m_bIsConnected = FALSE;
//连接出错,服务器和客户端连接已经断开,直接调用回调函数;
m_pNamedPipe->m_pCallbackFunc(NULL, 0, m_pNamedPipe->m_lpParam);
}
//设置hExitEvent事件;
SetEvent(m_pNamedPipe->m_hExitEvent);
//关闭句柄;
CloseHandle(m_pNamedPipe->m_hNamedPipe);
return 0;
}
//处理从管道中收到数据的工作线程函数;
UINT CNamedPipe::WorkerThrdFunc(LPVOID lpParam)
{
CNamedPipe * m_pNamedPipe = (CNamedPipe*)lpParam;
HANDLE hEvent[2] = {NULL};
hEvent[0] = m_pNamedPipe->m_hWorkEvent;
hEvent[1] = m_pNamedPipe->m_hExitEvent;
while (TRUE)
{
::EnterCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
//若队列为空,则等待hWorkEvent事件被设置;
if (m_pNamedPipe->m_lRecvDataQueue.IsEmpty())
{
::LeaveCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
//开始等待hWorkEvent被设置;
DWORD dwEventIndex = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE);
if ((dwEventIndex - WAIT_OBJECT_0) == 1)
{
//系统通知工作线程退出;
return 0;
}
}
else
{
//从链表头部取下一个节点;
DATA_NODE node = m_pNamedPipe->m_lRecvDataQueue.RemoveHead();
//离开临界区;
::LeaveCriticalSection(&m_pNamedPipe->m_csRecvDataQueue);
//调用回调函数;
m_pNamedPipe->m_pCallbackFunc(node.szBuffer, node.uiBufLength, m_pNamedPipe->m_lpParam);
}
}
return 0;
}
//向管道中写入待发送数据的发送现存函数;
UINT CNamedPipe::SenderThrdFunc(LPVOID lpParam)
{
CNamedPipe * m_pNamedPipe = (CNamedPipe*)lpParam;
HANDLE hEvent[2] = {NULL};
hEvent[0] = m_pNamedPipe->m_hSendEvent;
hEvent[1] = m_pNamedPipe->m_hExitEvent;
while (TRUE)
{
::EnterCriticalSection(&m_pNamedPipe->m_csSendDataQueue);
//若发送队列为空,则等待hSendEvent事件被设置;
if (m_pNamedPipe->m_lSendDataQueue.IsEmpty())
{
::LeaveCriticalSection(&m_pNamedPipe->m_csSendDataQueue);
DWORD dwEventIndex = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE);
if ((dwEventIndex - WAIT_OBJECT_0) == 1)
{
//收到hExitEvent被设置通知,则退出线程;
CloseHandle(m_pNamedPipe->m_hNamedPipe);
return 0;
}
}
else
{
//取下一个节点,并发送;
DATA_NODE node = m_pNamedPipe->m_lSendDataQueue.RemoveHead();
//释放发送链表临界区;
::LeaveCriticalSection(&m_pNamedPipe->m_csSendDataQueue);
DWORD dwRetLen = 0;
if (!WriteFile(m_pNamedPipe->m_hNamedPipe, node.szBuffer, node.uiBufLength, &dwRetLen, NULL) \
|| dwRetLen != node.uiBufLength)
{
GetLastError();
//向命名管道写数据错误;
}
}
}
if (m_pNamedPipe->m_bAsServer)
{
DisconnectNamedPipe(m_pNamedPipe->m_hNamedPipe);
CloseHandle(m_pNamedPipe->m_hNamedPipe);
}
else
{
CloseHandle(m_pNamedPipe->m_hNamedPipe);
}
return 0;
}