命名管道通讯遇到的问题,希望大家帮助

sidewalk 2005-04-24 11:28:43
自己最近写了个使用命名管道进行通讯的类,但是在使用的时候确出现问题,百思不解,现把情况说一下,希望大家给点意见,谢谢。
这个类中我使用三线程模型,对命名管道进行读写。其中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;
}
...全文
170 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
nuaawenlin 2005-04-25
  • 打赏
  • 举报
回复
感觉是你队临界区的操作影响了发送,好好调试,祝你好运
sidewalk 2005-04-24
  • 打赏
  • 举报
回复
自己顶一下!
sidewalk 2005-04-24
  • 打赏
  • 举报
回复

BOOL CNamedPipe::GetConnectStatus()
{
return m_bIsConnected;
}

unsigned long CNamedPipe::GetPipeBufferSize()
{
return PIPE_BUF_SIZE;
}
//向待发送链表中添加数据节点的函数;
BOOL CNamedPipe::Write(char *pszDataBuffer, unsigned long ulDataLength)
{
if (!m_bIsConnected || pszDataBuffer == NULL || ulDataLength == 0)
{
return FALSE;
}
//构造数据节点;
if (ulDataLength > PIPE_BUF_SIZE)
{
ulDataLength = PIPE_BUF_SIZE;
}
DATA_NODE node;
node.uiBufLength = ulDataLength;
memcpy(node.szBuffer, pszDataBuffer, ulDataLength);
//将节点插入发送数据链表尾部;
::EnterCriticalSection(&m_csSendDataQueue);
if (m_lSendDataQueue.IsEmpty())
{
m_lSendDataQueue.AddTail(node);
::LeaveCriticalSection(&m_csSendDataQueue);
//消息队列为空设置m_hSendEvent,告诉发送线程可以发送了;
SetEvent(m_hSendEvent);
}
else
{
m_lSendDataQueue.AddTail(node);
::LeaveCriticalSection(&m_csSendDataQueue);
}
return TRUE;
}
//初始化函数,参数一表示是否做为服务器端启动;参数二:回调函数,参数三:客户程序传入的单//句柄数据,参数四:管道名;参数五:主机名;
BOOL CNamedPipe::Init(BOOL bAsServer, fHandleDataFunc pfHandleFunc,
LPVOID lpParam, CString strName, CString strHost)
{
m_bAsServer = bAsServer;
if (!pfHandleFunc)
{
return FALSE;
}
if (lpParam)
{
m_lpParam = lpParam;
}
if (strName.IsEmpty())
{
return FALSE;
}
m_strFullPipeName = "\\\\" + strHost + "\\PIPE\\" + strName;
if (m_bAsServer)
{
//服务器;
//允许任何用户和用户组访问管道(不同的主机间);
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
//初始化新的SECURITY_DESCRIPTOR对象为空;
if (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) == 0)
{
GetLastError();
return FALSE;
}
//设置SECURITY_DESCRIPTOR对象的DACL域为Null;
if (SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE) == 0)
{
GetLastError();
return FALSE;
}
//将SECURTIY_DESCRIPTOR对象赋值给SECURITY_ATTRIBUTES对象;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = TRUE;
//创建命名管道服务器;
m_hNamedPipe = CreateNamedPipe(m_strFullPipeName,
PIPE_ACCESS_INBOUND|PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,
1,PIPE_BUF_SIZE,PIPE_BUF_SIZE,
PIPE_TIMEOUT,&sa);
if (m_hNamedPipe == NULL || m_hNamedPipe == INVALID_HANDLE_VALUE)
{
return FALSE;
}
}
else
{
//等待客户端连接到命名管道(阻塞方式);
BOOL bConnected = WaitNamedPipe(m_strFullPipeName, PIPE_TIMEOUT);
if (!bConnected)
{
return FALSE;
}
m_hNamedPipe = CreateFile(
m_strFullPipeName,
GENERIC_READ|GENERIC_WRITE,
0, //i.e. No Share
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (m_hNamedPipe == NULL || m_hNamedPipe == INVALID_HANDLE_VALUE)
{
return 2;
}
m_bIsConnected = TRUE; //服务器和客户端已经成功连接;
}
//创建接收线程;
m_pRecvThrd = AfxBeginThread(RecvThrdFunc, this);
if (m_pRecvThrd == NULL || m_pRecvThrd->m_hThread == INVALID_HANDLE_VALUE)
{
return FALSE;
}
//创建工作线程;
m_pWorkerThrd = AfxBeginThread(WorkerThrdFunc, this);
if (m_pWorkerThrd == NULL || m_pWorkerThrd->m_hThread == INVALID_HANDLE_VALUE)
{
return FALSE;
}
//创建发送线程;
m_pSenderThrd = AfxBeginThread(SenderThrdFunc, this);
if (m_pSenderThrd == NULL || m_pSenderThrd->m_hThread == INVALID_HANDLE_VALUE)
{
return FALSE;
}
return TRUE;
}

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧