管道服务器创建管道,管道客户端连接管道。
32位,64位之间可以混合通信,主要代码如下:
void CServerDlg::OnBnClickedButtonStartServer()
{
UpdateData(TRUE);
CString PipeFullPathData = L"\\\\.\\Pipe\\NamedPipePipe";
if (m_CEdit_Max_Connect_Count > 0 && m_CEdit_Max_Connect_Count < 100)
{
for (UINT i = 0; i < m_CEdit_Max_Connect_Count; i++)
{
// 创建管道实例
m_UserData[i].PipeHandle = CreateNamedPipe(PipeFullPathData, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, \
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, m_CEdit_Max_Connect_Count, 0, 0, 1000, NULL);
if (m_UserData[i].PipeHandle == INVALID_HANDLE_VALUE)
{
DWORD ErrorCode = GetLastError();
this->MessageBox(L"创建管道错误!");
return;
}
// 为每个管道实例创建一个事件对象,用于实现重叠IO
m_UserData[i].EventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
// 为每个管道实例分配一个线程,用于响应客户端的请求
m_UserData[i].ThreadHandle = AfxBeginThread(ThreadProcedure, &m_UserData[i], THREAD_PRIORITY_NORMAL);
}
{
this->SetWindowText(L"命名管道—服务器(运行)");
this->MessageBox(L"服务启动成功");
}
}
}
void CServerDlg::OnBnClickedButtonStopServer()
{
DWORD dwNewMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT;
for (UINT i = 0; i < m_CEdit_Max_Connect_Count; i++)
{
// 设置重叠I/O的事件,使得工作线程安全结束
SetEvent(m_UserData[i].EventHandle);
Sleep(1);
CloseHandle(m_UserData[i].ThreadHandle);
CloseHandle(m_UserData[i].PipeHandle);
}
this->SetWindowText(L"命名管道—服务器(停止)");
this->MessageBox(L"停止启动成功");
}
UINT ThreadProcedure(LPVOID ParameterData)
{
DWORD ReturnLength = 0;
char BufferData[0x400] = { 0 };
USER_DATA UserData = *(USER_DATA*)ParameterData;
OVERLAPPED Overlapped = { 0, 0, 0, 0, UserData.EventHandle};
while (1)
{
memset(BufferData, 0, sizeof(BufferData));
// 命名管道的连接函数,等待客户端的连接(只针对NT)
ConnectNamedPipe(UserData.PipeHandle, &Overlapped);
// 实现重叠I/0,等待OVERLAPPED结构的事件对象
WaitForSingleObject(UserData.EventHandle, INFINITE);
// 检测I/0是否已经完成,如果未完成,意味着该事件对象是人工设置,即服务需要停止
if (!GetOverlappedResult(UserData.PipeHandle, &Overlapped, &ReturnLength, true))
break;
// 从管道中读取客户端的请求信息
if (!ReadFile(UserData.PipeHandle, BufferData, 0x400, &ReturnLength, NULL))
{
MessageBox(0, L"读取管道错误!", 0, 0);
break;
}
int v1, v2;
sscanf(BufferData, "%d %d", &v1, &v2); //字符串转换为%d
__ServerDlg->m_v1 = v1;
__ServerDlg->m_v2 = v2;
__ServerDlg->m_v3 = v1 + v2;
memset(BufferData, 0, sizeof(BufferData));
sprintf(BufferData, "%d", __ServerDlg->m_v3);
// 把反馈信息写入管道
WriteFile(UserData.PipeHandle, BufferData, strlen(BufferData), &ReturnLength, NULL);
__ServerDlg->SetDlgItemInt(IDC_EDIT_V1, v1, true);
__ServerDlg->SetDlgItemInt(IDC_EDIT_V2, v2, true);
__ServerDlg->SetDlgItemInt(IDC_EDIT_V3, __ServerDlg->m_v3, true);
// 断开客户端的连接,以便等待下一客户的到来
DisconnectNamedPipe(UserData.PipeHandle);
}
return 0;
}
void CClientDlg::OnBnClickedButtonSubmitClient()
{
// TODO: 在此添加控件通知处理程序代码
HANDLE NamedPipeHandle = CreateFile(L"\\\\.\\Pipe\\NamedPipePipe", GENERIC_READ | GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (NamedPipeHandle == INVALID_HANDLE_VALUE)
{
this->MessageBox(L"打开管道失败,服务器尚未启动,或者客户端数量过多");
return;
}
DWORD ReturnLength = 0;
char BufferData[0x400] = { 0 };
// 把两个整数(a,b)格式化为字符串
m_v1 = GetDlgItemInt(IDC_EDIT_V1);
m_v2 = GetDlgItemInt(IDC_EDIT_V2);
sprintf(BufferData, "%d %d", this->m_v1, this->m_v2);
// 把数据写入管道
WriteFile(NamedPipeHandle, BufferData, strlen(BufferData), &ReturnLength, NULL);
memset(BufferData, 0,0x400);
// 读取服务器的反馈信息
ReadFile(NamedPipeHandle, BufferData, 0x400, &ReturnLength, NULL);
sscanf(BufferData, "%d", &(this->m_v3));
SetDlgItemInt(IDC_EDIT_V3, m_v3, true);
CloseHandle(NamedPipeHandle);
}
//清空
void CClientDlg::OnBnClickedButtonEmptyClient()
{
// TODO: 在此添加控件通知处理程序代码
this->SetDlgItemInt(IDC_EDIT_V1, NULL, true);
this->SetDlgItemInt(IDC_EDIT_V2, NULL, true);
this->SetDlgItemInt(IDC_EDIT_V3, NULL, true);
}