windows channel

来源:互联网 发布:图片放去噪算法 编辑:程序博客网 时间:2024/06/11 22:38

BlockQueue.h

#pragma once#include "Common.h"#include "Condition.h"template<typename T>class BlockQueue{public:BlockQueue(): mutex_(), notEmpty_(mutex_){}void put(const T &t){MutexLockGuard lock(mutex_);queue_.push_back(t);notEmpty_.notify();}T take(){MutexLockGuard lock(mutex_);while (queue_.empty()) {notEmpty_.wait();}assert(!queue_.empty());T front(queue_.front());queue_.pop_front();return front;}size_t size() const{MutexLockGuard lock(mutex_);return queue_.size(); }private:BlockQueue(const BlockQueue&);BlockQueue& operator=(const BlockQueue&);private:mutable MutexLock mutex_;Condition notEmpty_;std::deque<T> queue_;};

Buffer.h

#pragma once#include "Common.h"class Buffer;typedef std::tr1::shared_ptr<Buffer> BufferPtr;class Buffer{public:  static const size_t kCheapPrepend = 8;  static const size_t kInitialSize = 2048;  Buffer() : buffer_(kCheapPrepend + kInitialSize) , readerIndex_(kCheapPrepend) , writerIndex_(kCheapPrepend){assert(readableBytes() == 0);assert(writableBytes() == kInitialSize);assert(prependableBytes() == kCheapPrepend);}void swap(Buffer &rhs){buffer_.swap(rhs.buffer_);std::swap(readerIndex_, rhs.readerIndex_);std::swap(writerIndex_, rhs.writerIndex_);}size_t readableBytes() const{return writerIndex_ - readerIndex_; }size_t writableBytes() const{return buffer_.size() - writerIndex_;}size_t prependableBytes() const{return readerIndex_;}const char *peek() const{return begin() + readerIndex_;}void retrieve(size_t len){assert(len <= readableBytes());if ( len < readableBytes()){readerIndex_ += len;}else{retrieveAll();}}void retrieveUntil(const char *end){assert(peek() <= end);assert(end <= beginWrite());retrieve(end - peek());}void retrieveInt32(){retrieve(sizeof(__int32));}void retrieveInt16(){retrieve(sizeof(__int16));}void retrieveInt8(){retrieve(sizeof(__int8));}void retrieveAll(){readerIndex_ = kCheapPrepend;writerIndex_ = kCheapPrepend;}std::string retrieveAllAsString(){return retrieveAsString(readableBytes());}std::string retrieveAsString(size_t len){assert(len <= readableBytes());std::string result(peek(), len);retrieve(len);return result;}void append(const std::string &str){append(str.c_str(), str.size());}void append(const char* data, size_t len){ensureWritableBytes(len);std::copy(data, data+len, stdext::checked_array_iterator<char*>(beginWrite(), len));hasWritten(len);}void append(const void* data, size_t len){append(static_cast<const char*>(data), len);}void ensureWritableBytes(size_t len){if (writableBytes() < len){makeSpace(len);}assert(writableBytes() >= len);}char* beginWrite(){return begin() + writerIndex_;}const char* beginWrite() const{return begin() + writerIndex_;}void hasWritten(size_t len){writerIndex_ += len;}void appendInt32(__int32 x);void appendInt16(__int16 x);void appendInt8(__int8 x);__int32 readInt32();__int16 readInt16();__int8 readInt8();__int32 peekInt32() const;__int16 peekInt16() const;__int8 peekInt8() const;void prependInt32(__int32 x);void prependInt16(__int16 x);void prependInt8(__int8 x);bool Buffer::read(void* data, size_t len){if (data && readableBytes() >= len){memcpy(data, peek(), len);retrieve(len);return true;}return false;}void prepend(const void* data, size_t len){assert(len <= prependableBytes());readerIndex_ -= len;const char *d = static_cast<const char*>(data);std::copy(d, d+len, stdext::checked_array_iterator<char*>(begin()+readerIndex_, len));}int readFd(void* fd, int *saveErrno);private:char *begin(){return &*buffer_.begin();}const char* begin() const{return &*buffer_.begin();}void makeSpace(size_t len){if (writableBytes() + prependableBytes() < len + kCheapPrepend){buffer_.resize(writerIndex_ + len);}else{assert(kCheapPrepend < readerIndex_);size_t readable = readableBytes();std::copy(begin() + readerIndex_, begin() + writerIndex_,stdext::checked_array_iterator<char*>(begin() + kCheapPrepend, writerIndex_ - readerIndex_));readerIndex_ = kCheapPrepend;writerIndex_ = readerIndex_ + readable;assert(readable == readableBytes());}}Buffer(const Buffer&);const Buffer& operator=(const Buffer&);private:std::vector<char> buffer_;size_t readerIndex_;size_t writerIndex_;};

Channel.h

#pragma once#include "Buffer.h"#include "BlockQueue.h"#define TCPCONN_SUCCESS0#define TCPCONN_ERROR_BASE0x00100#define TCPCONN_ERROR_SOCKETTCPCONN_ERROR_BASE + 1#define TCPCONN_ERROR_CONNECTTCPCONN_ERROR_BASE + 2#define TCPCONN_ERROR_SENDTCPCONN_ERROR_BASE + 3#define TCPCONN_ERROR_RECVTCPCONN_ERROR_BASE + 4#define TCPCONN_ERROR_WSAEVENTSELECTTCPCONN_ERROR_BASE + 5#define TCPCONN_ERROR_WSAENUMNETWORKEVENTSTCPCONN_ERROR_BASE + 6#define TCPCONN_ERROR_WSAWAITFORMULTIPLEEVENTSTCPCONN_ERROR_BASE + 7typedef std::tr1::function<void(Buffer&)> OnReadCallback;typedef std::tr1::function<void(int)> OnErrorCallback;typedef std::tr1::function<void()> OnCloseCallback;class Connector;class Thread;template<typename T> class BlockQueue;typedef std::tr1::shared_ptr<Connector> ConnectorPtr;class Channel{public:Channel(ConnectorPtr connectorPtr);~Channel();void start();void stop();void send(const unsigned char *msg, size_t len);void send(const BufferPtr &msg);void setOnReadCallback(const OnReadCallback &cb) { onReadCallback_ = cb; }void setOnErrorCallback(const OnErrorCallback &cb) { onErrorCallback_ = cb; }void setOnCloseCallback(const OnCloseCallback &cb) { onCloseCallback_ = cb; }private:Channel(const Channel&);Channel& operator=(const Channel&);void sendBufferThread();void recvBufferThread();private:ConnectorPtr connectorPtr_;scoped_ptr<Thread> recvBufferThread_;scoped_ptr<Thread> sendBufferThread_;scoped_ptr<BlockQueue<BufferPtr> > sendQueue_;Buffer recvBuffer_;OnReadCallback onReadCallback_;OnErrorCallback onErrorCallback_;OnCloseCallback onCloseCallback_;};

Common.h

#pragma once#include <assert.h>#include <stdlib.h>#include <cstddef>#include <string.h>#include <memory>#include <functional>#include <string>#include <deque>#include <algorithm>#include <vector>#include <map>#include <iterator>#include <WinSock2.h>#include <Windows.h>#include <iostream> // for testnamespace internal {//  This is an implementation designed to match the anticipated future TR2//  implementation of the scoped_ptr class, and its closely-related brethren,//  scoped_array, scoped_ptr_malloc, and make_scoped_ptr.template <class C> class scoped_ptr;template <class C> class scoped_array;// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>// automatically deletes the pointer it holds (if any).// That is, scoped_ptr<T> owns the T object that it points to.// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.//// The size of a scoped_ptr is small:// sizeof(scoped_ptr<C>) == sizeof(C*)template <class C>class scoped_ptr { public:  // The element type  typedef C element_type;  // Constructor.  Defaults to intializing with NULL.  // There is no way to create an uninitialized scoped_ptr.  // The input parameter must be allocated with new.  explicit scoped_ptr(C* p = NULL) : ptr_(p) { }  // Destructor.  If there is a C object, delete it.  // We don't need to test ptr_ == NULL because C++ does that for us.  ~scoped_ptr() {    enum { type_must_be_complete = sizeof(C) };    delete ptr_;  }  // Reset.  Deletes the current owned object, if any.  // Then takes ownership of a new object, if given.  // this->reset(this->get()) works.  void reset(C* p = NULL) {    if (p != ptr_) {      enum { type_must_be_complete = sizeof(C) };      delete ptr_;      ptr_ = p;    }  }  // Accessors to get the owned object.  // operator* and operator-> will assert() if there is no current object.  C& operator*() const {    assert(ptr_ != NULL);    return *ptr_;  }  C* operator->() const  {    assert(ptr_ != NULL);    return ptr_;  }  C* get() const { return ptr_; }  // Comparison operators.  // These return whether two scoped_ptr refer to the same object, not just to  // two different but equal objects.  bool operator==(C* p) const { return ptr_ == p; }  bool operator!=(C* p) const { return ptr_ != p; }  // Swap two scoped pointers.  void swap(scoped_ptr& p2) {    C* tmp = ptr_;    ptr_ = p2.ptr_;    p2.ptr_ = tmp;  }  // Release a pointer.  // The return value is the current pointer held by this object.  // If this object holds a NULL pointer, the return value is NULL.  // After this operation, this object will hold a NULL pointer,  // and will not own the object any more.  C* release() {    C* retVal = ptr_;    ptr_ = NULL;    return retVal;  } private:  C* ptr_;  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't  // make sense, and if C2 == C, it still doesn't make sense because you should  // never have the same object owned by two different scoped_ptrs.  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;  // Disallow evil constructors  scoped_ptr(const scoped_ptr&);  void operator=(const scoped_ptr&);};// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate// with new [] and the destructor deletes objects with delete [].//// As with scoped_ptr<C>, a scoped_array<C> either points to an object// or is NULL.  A scoped_array<C> owns the object that it points to.//// Size: sizeof(scoped_array<C>) == sizeof(C*)template <class C>class scoped_array { public:  // The element type  typedef C element_type;  // Constructor.  Defaults to intializing with NULL.  // There is no way to create an uninitialized scoped_array.  // The input parameter must be allocated with new [].  explicit scoped_array(C* p = NULL) : array_(p) { }  // Destructor.  If there is a C object, delete it.  // We don't need to test ptr_ == NULL because C++ does that for us.  ~scoped_array() {    enum { type_must_be_complete = sizeof(C) };    delete[] array_;  }  // Reset.  Deletes the current owned object, if any.  // Then takes ownership of a new object, if given.  // this->reset(this->get()) works.  void reset(C* p = NULL) {    if (p != array_) {      enum { type_must_be_complete = sizeof(C) };      delete[] array_;      array_ = p;    }  }  // Get one element of the current object.  // Will assert() if there is no current object, or index i is negative.  C& operator[](std::ptrdiff_t i) const {    assert(i >= 0);    assert(array_ != NULL);    return array_[i];  }  // Get a pointer to the zeroth element of the current object.  // If there is no current object, return NULL.  C* get() const {    return array_;  }  // Comparison operators.  // These return whether two scoped_array refer to the same object, not just to  // two different but equal objects.  bool operator==(C* p) const { return array_ == p; }  bool operator!=(C* p) const { return array_ != p; }  // Swap two scoped arrays.  void swap(scoped_array& p2) {    C* tmp = array_;    array_ = p2.array_;    p2.array_ = tmp;  }  // Release an array.  // The return value is the current pointer held by this object.  // If this object holds a NULL pointer, the return value is NULL.  // After this operation, this object will hold a NULL pointer,  // and will not own the object any more.  C* release() {    C* retVal = array_;    array_ = NULL;    return retVal;  } private:  C* array_;  // Forbid comparison of different scoped_array types.  template <class C2> bool operator==(scoped_array<C2> const& p2) const;  template <class C2> bool operator!=(scoped_array<C2> const& p2) const;  // Disallow evil constructors  scoped_array(const scoped_array&);  void operator=(const scoped_array&);};}  // namespace internal// We made these internal so that they would show up as such in the docs,// but we don't want to stick "internal::" in front of them everywhere.using internal::scoped_ptr;using internal::scoped_array;

Condition.h

#pragma once#include "MutexLock.h"class Condition{public:explicit Condition(MutexLock &mutex): mutex_(mutex){InitializeConditionVariable(&cond_);}void wait(){SleepConditionVariableCS(&cond_, &mutex_.cs(), INFINITE);}void notify(){WakeConditionVariable(&cond_);}private:Condition(const Condition&);Condition& operator=(const Condition&);private:MutexLock &mutex_;CONDITION_VARIABLE cond_;};

Connector.h

#pragma once#include "Common.h"class Connector{public:typedef std::tr1::function<void(SOCKET fd)> ConnectionCallback;Connector(const std::string &ip, unsigned short port);virtual ~Connector(void);virtual void start();virtual void stop();void setConnectionCallback(const ConnectionCallback &func) { func_ = func; }SOCKET socket() const { return sock_; }bool connected() const { return connected_; }private:void connect();private:std::string ip_;unsigned short port_;ConnectionCallback func_;SOCKET sock_;bool connected_;};

MutexLock.h

#pragma once#include <WinBase.h>class MutexLock{public:MutexLock(){InitializeCriticalSection(&criticalSection_);}~MutexLock(){DeleteCriticalSection(&criticalSection_);}void lock(){EnterCriticalSection(&criticalSection_);}void unlock(){LeaveCriticalSection(&criticalSection_);}CRITICAL_SECTION& cs(){return criticalSection_;}private:MutexLock(const MutexLock&);MutexLock& operator=(const MutexLock&);CRITICAL_SECTION criticalSection_;};class MutexLockGuard{public:explicit MutexLockGuard(MutexLock &mutex): mutex_(mutex){mutex_.lock();}~MutexLockGuard(){mutex_.unlock();}private:MutexLockGuard(const MutexLockGuard&);MutexLockGuard operator=(const MutexLockGuard&);MutexLock& mutex_;};

Thread.h

#pragma once#include "Common.h"class Thread{public:typedef std::tr1::function<void()> ThreadFunc;explicit Thread(const ThreadFunc&, const std::string &name=std::string());~Thread();void start();int join();bool started() const { return started_; }HANDLE handle() const { return handle_; }unsigned int tid() const { return tid_; }const std::string& name() const { return name_; }private:static unsigned int WINAPI startThread(void *data);void runInThread();private:HANDLE handle_;unsigned int tid_;bool started_;ThreadFunc func_;std::string name_;};

WSAStartup.h

#pragma onceclass WsaStartup{public:WsaStartup(unsigned char majorVer, unsigned char minorVer);virtual ~WsaStartup(void);};
Buffer.cpp

#include "Buffer.h"#include <WinSock2.h>void Buffer::appendInt32(__int32 x){__int32 be32 = htonl(x);append(&be32, sizeof(be32));}void Buffer::appendInt16(__int16 x){__int16 be16 = htons(x);append(&be16, sizeof(be16));}void Buffer::appendInt8(__int8 x){append(&x, sizeof(x));}__int32 Buffer::readInt32(){__int32 result = peekInt32();retrieveInt32();return result;}__int16 Buffer::readInt16(){__int16 result = peekInt16();retrieveInt16();return result;}__int8 Buffer::readInt8(){__int8 result = peekInt8();retrieveInt8();return result;}__int32 Buffer::peekInt32() const{assert(readableBytes() >= sizeof(__int32));__int32 be32 = 0;::memcpy(&be32, peek(), sizeof(be32));return ntohl(be32);}__int16 Buffer::peekInt16() const{assert(readableBytes() >= sizeof(__int16));__int16 be16 = 0;::memcpy(&be16, peek(), sizeof(be16));return htons(be16);}__int8 Buffer::peekInt8() const{assert(readableBytes() >= sizeof(__int8));__int8 x = *peek();return x;}void Buffer::prependInt32(__int32 x){__int32 be32 = htonl(x);prepend(&be32, sizeof(be32));}void Buffer::prependInt16(__int16 x){__int16 be16 = htons(x);prepend(&be16, sizeof(be16));}void Buffer::prependInt8(__int8 x){prepend(&x, sizeof(x));}int Buffer::readFd(void* fd, int *saveErrno){SOCKET sock = (SOCKET)fd;int writable = writableBytes();int n = ::recv(sock, begin() + writerIndex_, writable, 0);if (SOCKET_ERROR == n){*saveErrno = WSAGetLastError();}else if (n <= writable){writerIndex_ += n;}return n;}


Channel.cpp

#include "Channel.h"#include "Thread.h"#include "Connector.h"Channel::Channel(ConnectorPtr connectorPtr): connectorPtr_(connectorPtr), sendQueue_(new BlockQueue<BufferPtr>()){recvBufferThread_.reset(new Thread(std::tr1::bind(&Channel::recvBufferThread, this), "eventHandleThread"));sendBufferThread_.reset(new Thread(std::tr1::bind(&Channel::sendBufferThread, this), "sendBufferThread"));}Channel::~Channel(void){}void Channel::start(){connectorPtr_->start();recvBufferThread_->start();sendBufferThread_->start();}void Channel::stop(){connectorPtr_->stop();BufferPtr lastBufferPtr(new Buffer());sendQueue_->put(lastBufferPtr);recvBufferThread_->join();sendBufferThread_->join();sendQueue_.reset(new BlockQueue<BufferPtr>());}void Channel::send(const unsigned char *msg, size_t len){BufferPtr bufferPtr(new Buffer());bufferPtr->append(msg, len);sendQueue_->put(bufferPtr);}void Channel::send(const BufferPtr &msg){sendQueue_->put(msg);}void Channel::sendBufferThread(){std::cout << "recvBufferThread" << std::endl;while (connectorPtr_->connected()) {BufferPtr bufferPtr = sendQueue_->take();if (!connectorPtr_->connected()) {break;}unsigned int left = bufferPtr->readableBytes();while (left > 0) {int sendNum = ::send(connectorPtr_->socket(), bufferPtr->peek(), left, 0);if (SOCKET_ERROR == sendNum) {onErrorCallback_(TCPCONN_ERROR_SEND);break;}left -= sendNum;bufferPtr->retrieve(sendNum);}}std::cout << "recvBufferThread exit" << std::endl;}void Channel::recvBufferThread(){std::cout << "sendBufferThread" << std::endl;while (connectorPtr_->connected()) {static const int bufferLen = 65535;;char buffer[bufferLen];int recvNum = ::recv(connectorPtr_->socket(), buffer, bufferLen, 0);if (recvNum > 0) {recvBuffer_.append(buffer, recvNum);onReadCallback_(recvBuffer_);} else if (0 == recvNum) {onCloseCallback_();break;} else {onErrorCallback_(TCPCONN_ERROR_RECV);break;}}std::cout << "sendBufferThread exit" << std::endl;}
Connector.cpp

#include "Connector.h"#include <Windows.h>Connector::Connector(const std::string &ip, unsigned short port): ip_(ip), port_(port), func_(NULL), sock_(INVALID_SOCKET), connected_(false){}Connector::~Connector(void){stop();}void Connector::start(){connect();}void Connector::stop(){connected_ = false;if (INVALID_SOCKET != sock_) {::shutdown(sock_, 2); // FIXME::closesocket(sock_);sock_ = INVALID_SOCKET;}}void Connector::connect(){sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_addr.s_addr = inet_addr(ip_.c_str());sin.sin_port = htons(port_);sock_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET != sock_) {if (0 == ::connect(sock_, (SOCKADDR*)&sin, sizeof(sin))) {connected_ = true;} else {::closesocket(sock_);sock_ = INVALID_SOCKET;}}}

Thread.cpp

#include "Thread.h"#include <process.h>#include <assert.h>Thread::Thread(const ThreadFunc &func, const std::string &name): handle_(NULL), tid_(0), started_(false), func_(func), name_(name){}Thread::~Thread(){CloseHandle(handle_);}void Thread::start(){started_ = true;handle_ = (HANDLE)_beginthreadex(NULL, 0, startThread, this, 0, &tid_);assert(handle_ > 0);}int Thread::join(){if (GetCurrentThreadId() == tid_) {return 0;}return WaitForSingleObject(handle_, INFINITE);}unsigned int Thread::startThread(void *data){Thread *thread = static_cast<Thread*>(data);thread->runInThread();return 0;}void Thread::runInThread(){assert(GetCurrentThreadId() == tid_);if (func_) {func_();}started_ = false;}

WsaStartup.cpp

#include "WsaStartup.h"#include <Windows.h>#include <crtdbg.h>WsaStartup::WsaStartup(unsigned char majorVer, unsigned char minorVer){WSAData wsaData;_ASSERT(0 == WSAStartup(MAKEWORD(majorVer, minorVer), &wsaData));}WsaStartup::~WsaStartup(void){WSACleanup();}



0 0