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<[email protected]>
*/
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();
}
}
}