C++封装的NamedPipe服务端和客户端类

LocalSocket.h

#ifndef __SOCK_SERVER_H__
#define ___SOCK_SERVER_H__

#include "LocalSocket.h"

#include <queue>
#ifndef __LOCAL_SOCKET_SERVER__
#define __LOCAL_SOCKET_SERVER__

#include <windows.h>
#include <string>
#include <stdio.h>
#include <vector>
#include "list.h"
#include "error.h"

#define SYSTEM_MAX_PENDING_SOCKETS 8
#define BUFSIZE 0

using namespace std;
typedef HANDLE NamePipe;

class LocalSocketServer;
class LocalSocket;

struct Listener{
HANDLE handle;
OVERLAPPED overlapped;
bool connected;
};

class LocalSocketServer{
public:
LocalSocketServer();
~LocalSocketServer();
bool listen(string name);

void waitForNewConnection(int ms = INFINITE);
void closeServer();
LocalSocket* nextPendingConnection();
int currentConnections(){
return connections.size();
}
private:
HANDLE eventHandle;
string name;
List<Listener> listeners;
List<LocalSocket*> connections;
bool addListener();
void newConnection();
void incomingConnection(NamePipe handle);
};

class LocalSocket{
public:
LocalSocket(HANDLE handle = NULL);
~LocalSocket();
bool connect(string name);
string readAll();
bool waitReadReady(int ms = INFINITE);
int writeAll(string data);
bool isReadable();
void close();
int state();
private:
HANDLE pipe;
};
#endif



#include "LocalSocket.h"

LocalSocketServer::LocalSocketServer(){

}

LocalSocketServer::~LocalSocketServer(){
closeServer();
}

bool LocalSocketServer::addListener(){

SECURITY_ATTRIBUTES sa;
PSID worldSID = 0;
PSECURITY_DESCRIPTOR pSD = new SECURITY_DESCRIPTOR;

sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE; //non inheritable handle, same as default
sa.lpSecurityDescriptor = 0; //default securi

InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(pSD, TRUE, 0, FALSE);

HANDLE hToken = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)){
return false;
}

DWORD dwBufferSize = 0;
GetTokenInformation(hToken, TokenUser, 0, 0, &dwBufferSize);

PTOKEN_USER pTokenUser = (PTOKEN_USER)new BYTE[dwBufferSize];
memset(pTokenUser, 0, dwBufferSize);
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
CloseHandle(hToken);
return false;
}

dwBufferSize = 0;
GetTokenInformation(hToken, TokenPrimaryGroup, 0, 0, &dwBufferSize);
PTOKEN_PRIMARY_GROUP pTokenGroup = (PTOKEN_PRIMARY_GROUP)new BYTE[dwBufferSize];
memset(pTokenGroup, 0, dwBufferSize);
if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
CloseHandle(hToken);
return false;
}
CloseHandle(hToken);


SID_IDENTIFIER_AUTHORITY WorldAuth = { SECURITY_WORLD_SID_AUTHORITY };
if (!AllocateAndInitializeSid(&WorldAuth, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&worldSID)) {
return false;
}

//calculate size of ACL buffer
DWORD aclSize = sizeof(ACL)+((sizeof(ACCESS_ALLOWED_ACE)) * 3);
aclSize += GetLengthSid(pTokenUser->User.Sid) - sizeof(DWORD);
aclSize += GetLengthSid(pTokenGroup->PrimaryGroup) - sizeof(DWORD);
aclSize += GetLengthSid(worldSID) - sizeof(DWORD);
aclSize = (aclSize + (sizeof(DWORD)-1)) & 0xfffffffc;

PACL acl = (PACL)new BYTE[aclSize];
memset(acl, 0, aclSize);

InitializeAcl(acl, aclSize, ACL_REVISION_DS);

if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenUser->User.Sid)) {
FreeSid(worldSID);
return false;
}


if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenGroup->PrimaryGroup)) {
FreeSid(worldSID);
return false;
}

if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, worldSID)) {
FreeSid(worldSID);
return false;
}

SetSecurityDescriptorOwner(pSD, pTokenUser->User.Sid, FALSE);
SetSecurityDescriptorGroup(pSD, pTokenGroup->PrimaryGroup, FALSE);
if (!SetSecurityDescriptorDacl(pSD, TRUE, acl, FALSE)) {
FreeSid(worldSID);
printf("err:%s", lastError().c_str());
return false;
}

sa.lpSecurityDescriptor = pSD;


listeners.push(Listener());
Listener& listener = listeners.last();

Listener* li = &listener;

string pipeName = "\\\\.\\pipe\\";

pipeName.append(name);

//将string转为wchar_t
size_t origsize = pipeName.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(pipeName.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, pipeName.c_str(), _TRUNCATE);

listener.handle = CreateNamedPipe(
wcstring, // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
PIPE_READMODE_BYTE | // byte-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
1000, // client time-out
&sa);

free(wcstring);

if (listener.handle == INVALID_HANDLE_VALUE){
listeners.pop();
return false;
}

memset(&listener.overlapped, 0, sizeof(listener.overlapped));
listener.overlapped.hEvent = eventHandle;

if (!ConnectNamedPipe(listener.handle, &listener.overlapped)){

DWORD err = GetLastError();

switch (err) {

case ERROR_IO_PENDING:
listener.connected = false;
break;

case ERROR_PIPE_CONNECTED:
listener.connected = true;
SetEvent(eventHandle);
break;

default:
CloseHandle(listener.handle);
listeners.pop();
return false;
}
}
else{
SetEvent(eventHandle);
}

return true;
}

void LocalSocketServer::closeServer(){
for (int i = 0; i < listeners.size(); ++i)
CloseHandle(listeners[i].handle);
listeners.clear();

if (eventHandle){
CloseHandle(eventHandle);
}
}

bool LocalSocketServer::listen(string name){
this->name = name;

eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i){
if (!addListener()){
return false;
}
}

return true;
}

void LocalSocketServer::waitForNewConnection(int ms){
DWORD result = WaitForSingleObject(eventHandle, (ms == -1) ? INFINITE : ms);
if (result != WAIT_TIMEOUT){
newConnection();
}
}

void LocalSocketServer::newConnection(){

DWORD dummy = 0;

// Reset first, otherwise we could reset an event which was asserted
// immediately after we checked the conn status.
ResetEvent(eventHandle);

// Testing shows that there is indeed absolutely no guarantee which listener gets
// a client connection first, so there is no way around polling all of them.


for (int i = 0; i < listeners.size();) {

HANDLE handle = listeners[i].handle;
Listener& listener = listeners[i];

BOOL lapRes = GetOverlappedResult(handle, &listener.overlapped, &dummy, FALSE);
DWORD size = GetFileSize(handle, NULL);
if (listener.connected || lapRes){

listeners.remove(i);
addListener();
incomingConnection(handle);
}
else {
if (GetLastError() != ERROR_IO_INCOMPLETE) {
printf("err:%s\n", lastError().c_str());
return;
}

++i;
}
}
}

LocalSocket* LocalSocketServer::nextPendingConnection(){
if (connections.size() == 0){
return NULL;
}

LocalSocket* sock = connections[0];
connections.remove(0);

return sock;
}

void LocalSocketServer::incomingConnection(NamePipe handle){
LocalSocket* sock = new LocalSocket(handle);
connections.push(sock);
}

LocalSocket::LocalSocket(NamePipe handle){
this->pipe = handle;
}

LocalSocket::~LocalSocket(){
close();
}

bool LocalSocket::connect(string name){
string pipeName = "\\\\.\\pipe\\";
pipeName.append(name);
int buffsize = 1024;

//将string转为wchar_t
size_t origsize = pipeName.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t)*(pipeName.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, pipeName.c_str(), _TRUNCATE);

if (!WaitNamedPipe(wcstring, NMPWAIT_WAIT_FOREVER))
{
printf("命名管道实例:\"%s\"不存在\n", pipeName.c_str());
return false;
}

pipe = CreateFile(wcstring, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (pipe == INVALID_HANDLE_VALUE){
printf("err: %s\n", lastError().c_str());
return false;
}

free(wcstring);
return true;
}

bool LocalSocket::isReadable(){
DWORD filesize = GetFileSize(pipe, NULL);
return filesize > 0;
}
int LocalSocket::state(){

DWORD bytes;


if (PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL)){
return bytes;
}

return -1;
}

bool LocalSocket::waitReadReady(int ms /* = INFINITE */){
long count = 0;
while (true)
{
if (state() == -1){
return false;
}

if (isReadable()){
return true;
}

Sleep(10);
count++;

if (ms != INFINITE && count > ms){
break;
}
}

return false;
}


void LocalSocket::close(){
if (pipe != INVALID_HANDLE_VALUE){
DisconnectNamedPipe(pipe);
CloseHandle(pipe);
}
}

string LocalSocket::readAll(){

if (!pipe){
return "";
}

int bufferSize = 1024;


string result = string("");
char* buffer = new char[bufferSize + 1];
memset(buffer, 0, bufferSize);

DWORD readSize = 0;
bool isBreak = false;
while (true){

if (!isReadable()){
break;
}

BOOL res = ReadFile(pipe, buffer, bufferSize, &readSize, NULL);

result.append(buffer);
memset(buffer, 0, bufferSize);

if (res == FALSE){
printf("error: %s\n", lastError().c_str());
DWORD err = GetLastError();

switch (err){
case ERROR_IO_PENDING: break;
case ERROR_MORE_DATA: isBreak = true; break;
case ERROR_BROKEN_PIPE:
case ERROR_PIPE_NOT_CONNECTED: break;
default:break;
}

}

if (isBreak){
break;
}
}

delete[] buffer;

return result;
}

int LocalSocket::writeAll(string data){
if (!pipe){
return 0;
}

DWORD writeSize = 0;
BOOL res = WriteFile(pipe, data.c_str(), data.length(), &writeSize, NULL);
if (res == FALSE){
printf("write file error!");
}

return writeSize;
}



lastError是个调试的方法,打印出当前的错误,省略了

List类,用STL自带那个,会有点问题,初步猜测是存值和存地址的问题,于是重新写了建德的列表类

list.h

#ifndef __LOCAL_LIST_H__
#define __LOCAL_LIST_H__

#include <stdio.h>
#include <string.h>

/**
* 张彪的list类,类中的元素存储的是值
* @author norkts<norkts@gmail.com>
*/

template <class T>
class List{
public:
List();
~List();
/**
* 添加新元素
*/
void append(T& t);

/**
* 移除新元素
*/
void remove(int index);

/**
* 添加新元素
*/
void push(T& t);

/**
* 移除最好一个元素
*/
void pop();
T& operator [](int index);

/**
* 获取最后一个元素
*/
T& last();

/**
* 列表大小
*/
int size();
int length();

/**
* 清空列表
*/
void clear();
private:
T** m_datas; //数据指针
int m_size; //列表元素数目
int m_maxSize; //元素最大个数
};


template <class T>
List<T>::List(){
m_maxSize = 1000;
m_size = 0;
m_datas = new T*[m_maxSize]();
}

template <class T>
List<T>::~List(){
clear();
}

template <class T>
void List<T>::append(T& t){

if (m_size >= m_maxSize){
m_maxSize = m_maxSize * 2; //扩展最大个数

T** newDatas = new T*[m_maxSize * 2]();
memcpy(newDatas, m_datas, sizeof(m_datas));

delete[] m_datas;

m_datas = newDatas;
}

*(m_datas + m_size) = new T();
memcpy(*(m_datas + m_size), &t, sizeof(T)); //复制值

m_size++;
}

template <class T>
int List<T>::size(){
return m_size;
}

template <class T>
int List<T>::length(){
return size();
}

template <class T>
void List<T>::remove(int index){

T *item = *(m_datas + index);
delete item;
memcpy(m_datas + index, m_datas + index + 1, sizeof(T*)* (m_size - index));//将后面的元素前移
m_size--;
}

template <class T>
T& List<T>::operator [](int index){
return **(m_datas + index);
}


template <class T>
void List<T>::push(T& t){
return append(t);
}

template <class T>
void List<T>::pop(){
return remove(size() - 1);
}

template <class T>
T& List<T>::last(){
return **(m_datas + size() - 1);
}

template <class T>
void List<T>::clear(){
delete[] m_datas;
}

#endif


example

int main(){

LocalSocketServer server;
server.listen("fgt-js-message");

while (true){

server.waitForNewConnection();
if (server.currentConnections() > 0){
LocalSocket* sock = server.nextPendingConnection();

while (true)
{
sock->waitReadReady();
string data = sock->readAll();
printf("%s\n", data.c_str());
if (sock->state() == -1){
break;
}
}

sock->close();
}


}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值