`

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();
}


}

}
分享到:
评论

相关推荐

    C++高性能http服务端和客户端库源码.zip

    一个C++高性能http服务端和客户端库,个C++高性能http服务端和客户端库一个C++高性能http服务端和客户端库 一个C++高性能http服务端和客户端库 一个C++高性能http服务端和客户端库 一个C++高性能http服务端和客户端...

    新项目基于TCP Socket实现的多线程聊天室程序c++源码(含服务端+客户端).zip

    新项目基于TCP Socket实现的多线程聊天室程序c++源码(含服务端+客户端).zip新项目基于TCP Socket实现的多线程聊天室程序c++源码(含服务端+客户端).zip新项目基于TCP Socket实现的多线程聊天室程序c++源码(含服务端+...

    c++ tcp 程序(含服务端和客户端源码)

    本资源提供的“c++ tcp 程序(含服务端和客户端源码)”是一个学习和实践C++ TCP编程的绝佳示例。 首先,我们来深入理解TCP协议。TCP通过三次握手建立连接,确保数据传输前双方已经准备好。在数据传输过程中,TCP会...

    基于C++和POLL的服务端和客户端源码(含项目说明+详细注释).zip

    基于C++和POLL的服务端和客户端源码(含项目说明+详细注释).zip LINUX网络编程部分开源项目学习和改进 ## 一、基于C++和POLL的服务端和客户端 &emsp;&emsp;1)文献来源:《Linux高性能服务器编程》——游双著;\ &...

    udp 服务端和客户端,c++

    标题中的“udp 服务端和客户端,c++”指的是使用C++编程语言实现UDP(User Datagram Protocol)协议的服务端和客户端程序。UDP是传输层的一种无连接、不可靠的协议,常用于实时数据传输,如视频流、语音通话等场景。...

    一个C++高性能http服务端和客户端库 支持http2协议,http1长连接

    本文将深入探讨标题和描述中提到的"一个C++高性能http服务端和客户端库,支持http2协议,http1长连接"这一主题。 首先,HTTP(超文本传输协议)是互联网上应用最为广泛的一种网络协议,它定义了客户端和服务器之间...

    服务端和客户端,java,C++实现代码

    在C++中,服务端和客户端的实现则需要更底层的网络API,如套接字(Sockets)库。在C++中,可以使用标准模板库(STL)和Boost库来辅助实现,但基本的网络操作仍依赖于系统级别的socket接口。服务端会创建一个监听套接字...

    【最新】C++ http post的服务端客户端

    本文将深入探讨如何使用C++实现HTTP POST服务端和客户端,特别是涉及JSON格式的数据交换。 首先,HTTP POST是Web服务中最常用的方法之一,用于向服务器发送数据。在C++中实现HTTP POST,你需要理解HTTP协议的基本...

    C++Socket编程实例(服务端跟客户端通信).rar

    通过学习这个实例,开发者不仅可以理解 C++ Socket 编程的基本原理,还能掌握服务端和客户端的通信流程,为更复杂的网络应用开发打下基础。实践中,还可以尝试实现更丰富的功能,比如加密通信、断线重连、数据压缩等...

    C++实现网络编程 服务端与客户端原代码

    根据提供的文件信息,我们可以深入探讨如何使用C++实现网络编程中的服务端与客户端,并通过具体的代码片段来理解其中的关键概念和技术细节。 ### C++ 实现网络编程基础 #### Socket 编程简介 Socket编程是实现...

    windows visual studio c++ tcp网络编程,包含服务端和客户端

    本篇将深入探讨如何使用Visual Studio C++进行TCP网络编程,涵盖服务端和客户端的实现。 一、TCP协议简介 TCP是一种面向连接的传输层协议,它确保了数据的顺序传输和错误检查,通过三次握手建立连接,并在四次挥手...

    C++实现http客户端连接服务端及客户端json数据的解析

    此代码用c++实现了http客户端的编写,其中包括了多字节转utf8(已在ExecuteRequest函数中实现,不用再引用所给的编码转换),get和post两种请求方式,后面有json数据的解析以及实现,详情可去博客...

    c++ socket编程实例(服务端及客户端)

    本实例提供了C++实现的服务端(server.cpp)和客户端(client.cpp),让我们深入探讨这个主题。 首先,C++中的Socket编程通常涉及两个主要部分:服务器端和客户端。服务器端负责监听特定的端口,等待客户端连接,并处理...

    Linux下TCP通信测试代码,包含服务端和客户端

    本压缩包提供了一份在Linux环境下实现TCP通信的示例代码,包括服务端和客户端的实现。 服务端实现: 服务端程序是TCP通信的起点,它创建一个监听套接字,并绑定到特定的IP地址和端口号上。通过调用`socket()`函数...

    用C++实现的websocket的服务端和客户端代码

    用C++实现的websocket的服务端和客户端代码

    基于C++的电子邮件系统服务端与客户端设计源码

    该项目是基于C++的电子邮件系统服务端与客户端设计源码,共包含73个文件,其中包括18个头文件(.h)、15个C++源文件(.cc)、8个C++源文件(.cpp)、6个Code::Blocks项目文件(.cbp)、6个依赖文件(.depend)、6个...

    c++ udp 程序(含服务端和客户端源码)

    下面将详细解释C++中实现UDP服务端和客户端程序的关键知识点。 首先,了解UDP的基本概念至关重要。与TCP(传输控制协议)不同,UDP不保证数据包的顺序、完整性和可靠性,而是以尽可能快的速度发送数据,因此适用于...

    基于C++和QtWebApp的文件快传Windows HTTP项目完整源码(含服务端+客户端)+项目说明.zip

    基于C++和QtWebApp的文件快传Windows HTTP项目完整源码(含服务端+客户端)+项目说明.zip基于C++和QtWebApp的文件快传Windows HTTP项目完整源码(含服务端+客户端)+项目说明.zip基于C++和QtWebApp的文件快传Windows ...

Global site tag (gtag.js) - Google Analytics