`

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

    博客分类:
  • c++
阅读更多
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();
}


}

}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics