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