多线程命名管道
来源:互联网 发布:单片机编程经典pdf 编辑:程序博客网 时间:2024/05/22 13:05
由于项目要求,迫切需要掌握多线程通信的技术,参考了网上的一些好文章,实现了多线程命名管道。我尽量把注释写全一些,这样读者看起来要轻松一些。
一、服务器端的实现。
服务器端完成以下几项工作:
1、创建多线程,每一个线程处理一个客户机的请求,可以满足多个客户端同时连接到服务器。
2、每一个线程负责连接一个客户机,并创建一个命名管道。
3、每一个命名管道创建一个监听程序,以服务客户机。
4、当有客户机退出连接时,服务器应该重新建立一个服务线程,以维持总的活跃管道数量不变。
服务器端代码如下,有详尽的注释,比较容易理解。
#include "stdafx.h"#include <Windows.h>#include <stdio.h>#include <conio.h>#define BUFFERSIZE 256 //缓冲区大小#define MAX_NUM_PIPES 5 //线程个数,即允许同时连接的客户机个数DWORD WINAPI PipeInstanceProc(LPVOID lpParameter); //多线程回调函数DWORD WINAPI ListenPipeProc(LPVOID lpParameter); //监听管道回调函数int _tmain(int argc, _TCHAR* argv[]){ HANDLE hThreadHandle;//线程句柄 DWORD threadId;//线程号 //创建五个线程,分别处理一个客户机连接 for (int i=0;i<MAX_NUM_PIPES;i++) { hThreadHandle=CreateThread( NULL,//WinNT后永久设为NULL 0,//线程初始化堆栈大小,一般设为0 PipeInstanceProc,//线程回调函数的指针,即函数名 NULL,//传输给回调函数的参数,通过它实现对回调函数的控制 0,//线程创建完毕后的状态,0表示创建后执行线程,CREATE_SUSPENDED表示暂时挂起,等待叫醒 &threadId//线程ID值的地址 ); if(hThreadHandle==NULL) { printf("创建线程%d失败!%d\n",i,GetLastError()); return 0; } printf("创建命名管道线程%d成功!",i); } //等待线程结束 WaitForSingleObject(hThreadHandle,INFINITE); CloseHandle(hThreadHandle); hThreadHandle=NULL; return 0;}/** 函数名称: PipeInstanceProc* 函数参数: (in)LPVOID: 附加信息* 函数作用: 处理一个命名管道实例的线程* 函数返回值:(DWORD)若顺利完成,则返回1;若获取域名失败,则返回0*/DWORD WINAPI PipeInstanceProc(LPVOID lpParameter){ HANDLE hPipeHandle;//命名管道的句柄 HANDLE hThreadListen;//管道监听句柄 /* * 函数名称: CreateNamedPipe * 函数参数: (in)LPCTSTR 命名管道名字,UNC标准( \\IP地址\Pipe\唯一标识文件路径 ) * (in)DWORD 命名管道模式,单双向,读写控制,安全模式( 均被宏定义好,可位或操作 ) * (in)DWORD 命名管道读,写,等待模式( 均被宏定义好,可位或操作 ) * (in)DWORD 命名管道最多可创建的实例句柄个数 * (in)DWORD 命名管道输出缓冲区大小 * (in)DWORD 命名管道输入缓冲区大小 * (in)DWORD 命名管道默认超时时间 * (in)LPSECURITY_ATTRIBUTES 命名管道安全描述符,若为NULL,则句柄不可继承的默认安全。 * 函数作用: 创建一个命名管道实例 * 函数返回值:(HANDLE)成功则返回命名管道实例的句柄,失败则返回值INVALID_HANDLE_VALUE */ hPipeHandle = CreateNamedPipe( _T("\\\\.\\pipe\\TrackerService"), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFFERSIZE, BUFFERSIZE, 0, NULL ); if (hPipeHandle == INVALID_HANDLE_VALUE) { printf("创建命名管道失败!%d\n",GetLastError()); return 0; } printf("创建命名管道成功!\n"); HANDLE h;//线程句柄,用于一个客户机退出连接之后,服务器重新建立一个服务线程 //处理客户端信息 while (1) { /* * 函数名称: ConnectNamedPipe * 函数参数: (in)HANDLE: 命名管道实例句柄 * (in)LPOVERLAPPED 是否锁定式命名管道 * 函数作用: 建立命名管道连接并监听 * 函数返回值:(bool)若顺利建立,则返回true;若顺利失败,则返回false */ if (ConnectNamedPipe(hPipeHandle,NULL)) { printf("有客户端连接命名管道!\n"); //Create listen pipe thread hThreadListen = CreateThread( NULL, 0, ListenPipeProc, hPipeHandle, 0, NULL ); if (hThreadListen==NULL) { printf("创建监听线程失败!\n"); return 0; } printf("创建监听线程成功!\n"); WaitForSingleObject(hThreadListen,INFINITE); //Close handle CloseHandle(hThreadListen); //set handle null hThreadListen = NULL; } else { printf("有客户端断开连接!%d\n",GetLastError()); DWORD threadId; //服务器重新建立一个服务线程 h=CreateThread( NULL,//WinNT后永久设为NULL 0,//线程初始化堆栈大小,一般设为0 PipeInstanceProc,//线程回调函数的指针,即函数名 NULL,//传输给回调函数的参数,通过它实现对回调函数的控制 0,//线程创建完毕后的状态,0表示创建后执行线程,CREATE_SUSPENDED表示暂时挂起,等待叫醒 &threadId//线程ID值的地址 ); if(h==NULL) { printf("创建线程失败!%d\n",GetLastError()); return 0; } printf("创建命名管道线程成功!"); WaitForSingleObject(h,INFINITE); CloseHandle(h); h=NULL; //销毁监听线程 CloseHandle(hThreadListen); return 0; } } CloseHandle(hPipeHandle); return 1;}DWORD WINAPI ListenPipeProc(LPVOID lpParameter){ DWORD nBytesWritten;//发出的写入信息字节数 char cBuffer[BUFFERSIZE]="The MultiThread Test!...........";//字节存储数组 BOOL fSuccess = FALSE; HANDLE hPipe=(HANDLE)lpParameter;//接收回调函数传来的参数 while (TRUE) { fSuccess= WriteFile( hPipe, cBuffer, sizeof(cBuffer), &nBytesWritten, NULL); if (!fSuccess) { break; } } //刷新缓冲区 FlushFileBuffers(hPipe); //断开命名管道的连接 if (DisconnectNamedPipe(hPipe) == 0) { printf("断开命名管道失败!%d\n",GetLastError()); CloseHandle(hPipe); return 0; } CloseHandle(hPipe); hPipe=NULL; return 1;}
二、客户机端的实现
客户机端完成以下工作:
1、检测服务器是否可以连接
2、打开命名管道
3、完成作业
客户机端代码如下:
#include "stdafx.h"#include <iostream>#include <Windows.h>int _tmain(int argc, _TCHAR* argv[]){ //检测服务器是否有命名管道可供连接 if (FALSE==WaitNamedPipe(_T("\\\\.\\pipe\\TrackerService"),NMPWAIT_WAIT_FOREVER)) { std::cout<<"不能连接到服务器\n"<<std::endl; return -1; } else { std::cout<<"连接服务器成功\n"<<std::endl; } //打开命名管道 HANDLE createHandle=CreateFile(_T("\\\\.\\pipe\\TrackerService"),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (createHandle==INVALID_HANDLE_VALUE) { std::cout<<"打开命名管道失败\n"<<std::endl; return -1; } else { std::cout<<"打开命名管道成功\n"<<std::endl; } int lpNumberOfBytesRead=0; char cBuffer[256]; //从服务器读取数据 if (ReadFile(createHandle,&cBuffer,sizeof(cBuffer),(LPDWORD)&lpNumberOfBytesRead,NULL)) { std::cout<<cBuffer<<std::endl; } CloseHandle(createHandle); return 0;}
- 多线程命名管道
- 多线程命名管道通信的设计
- 多线程命名管道通信的实现
- 多线程命名管道通信的设计
- [多线程命名管道服务器]Multithreaded Pipe Server
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- 命名管道
- STM32外设使用要点
- LIB和DLL的区别与使用
- 康奈尔大学做笔记方式
- mysql+memcached【续】
- Struts2.x+JFreeChart搭建框架出错(三)
- 多线程命名管道
- Poj 1067 取石子游戏(NIM,威佐夫博奕)
- hdu-人见人爱A^B
- linux下抓包--tcpdump的使用
- html5
- Codeforces Round #194 (Div. 2) 题解
- next数组的理解
- 使用Matlab绘制图像的rgb颜色空间和Lab颜色空间分量图和分量直方图
- 宏的高级应用