⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 packageserver.h

📁 C++ patterns设计模式
💻 H
字号:
#ifndef INCLUDED_PACKAGESERVER
#define INCLUDED_PACKAGESERVER

#if defined(HAS_PRAGMA_ONCE)
#pragma PRAGMA_ONCE_DECLARE
#endif

#include "tcpserver.h"
#include "packagebase.h"

namespace acl
{	
	template<typename PackageType>
	class PackageServer : public TcpServer					// server
						, public PackageBase<PackageType>	// queue support						
    {        
    public:
        PackageServer()
			: PackageBase<PackageType>(QUEUE_SIZE)
		{
		}

		PackageServer(u_short port, const char *addr = NULL)
			: TcpServer(port, addr)
			, PackageBase<PackageType>(QUEUE_SIZE)
		{
		}

		// convert stream into package, and put into queue
		bool queueStream(unsigned int clientId, protocol::BaseStream &stream)
		{
			PackageType *pkg = new PackageType;
			pkg->setConnectId(clientId);
            int startPos = 0;
            if(!packageWithSize())
            {
                startPos = 4;
            }
			if(!pkg->fromStream(stream, startPos))
				return false;
			putPackageAtTail(pkg);
			return true;
		}

		// send package to peer
		bool sendPackage(PackageType *pkg)
		{			
			assert(pkg);
			protocol::BaseStream stream;
			if(packageWithSize())
			{
				if(!pkg->toStream(stream))
					return false;
			}
			else
			{
				// convert package to stream
				protocol::BaseStream pkgStream;
				int length = 0;
				if(pkg->toStream(pkgStream))
				{
					length = pkgStream.size() - 4;
					// the real stream with length indicator
					stream.enc32(length);
					stream += pkgStream;
				}
				else
				{
					return false;
				}
			}
			return send(pkg->getConnectId(), stream.getBuffer(), stream.size()) == stream.size();
		}

	private:
        //onReceive must return the following result
        //RECV_OK             // recv ok
        //RECV_CLOSE          // connection closed
        //RECV_SOCKET_ERROR   // socket error
        //RECV_USER_ERROR     // user error < 0
        virtual int		onReceive(const TcpClientData &client);
        int  recvError(int ret);

    private:        
        enum
        {
            RECV_TIMEOUT = 5
        };
        enum
        {
            QUEUE_SIZE = 4096
        };
		enum 
		{
			MAX_PACKAGE_LENGTH = 4096
		};
    };

	//onReceive must return the recv result
	//RECV_OK             // recv ok
	//RECV_CLOSE          // connection closed
	//RECV_SOCKET_ERROR   // socket error
	//RECV_USER_ERROR     // user error < 0
	template<typename PackageType>
	int PackageServer<PackageType>::onReceive(const TcpClientData &client)
	{
		protocol::BaseStream stream;
		int  ret;

		//receive the package length at first!
		const AcceptedSocket &comm = client.m_socketid;
		stream.resize(4);
		ret = comm.recvAsyn(stream.getWriteBuffer(), stream.size(), RECV_TIMEOUT);

		//check valid header
		if(ret != 4)
		{
			if(ret > 0)
			{
				trace(client.m_clientid, "WRN:get package length failed, "
					"just received(%d) bytes\n", ret);
			}
			return recvError(ret);
		}
		//convert to host byte order
		u32 length;
		stream.dec32(length);
		stream.reset();			// reset the decode position
		u32 left = length;
		if(packageWithSize())
		{
			left -= 4;
		}
		//package can't just have the length field.
		if(left <= 0 || left >= MAX_PACKAGE_LENGTH)
		{
			trace(client.m_clientid, "WRN:invalid length(%d)\n", length);
			return RECV_USER_ERROR;
		}
		// allocate the new buffer
		stream.resize(stream.size() + left);
		// receive the left package data
        // "length" may include the length of header, and "left" is actually length to be received
        // length minus left equal 4 if packageWithSize() is true else equal 0
		ret = comm.recvAsyn(stream.getWriteBuffer(length-left), left, RECV_TIMEOUT);

		if(ret != left)
		{
			trace(client.m_clientid, "get left package failed, want(%d) but received(%d)\n",
				left, ret);

			return recvError(ret);
		}
		traceBinary(client.m_clientid, "received following buffer:\n", stream.getBuffer(), stream.size());
		if(!queueStream(client.m_clientid, stream))
		{
			trace(client.m_clientid, "stream error! I can't create package from it\n");
			return recvError(ret);
		}
		return RECV_OK;
	}

	template<typename PackageType>
	int  PackageServer<PackageType>::recvError(int ret)
	{
		if(ret == 0)
			return RECV_CLOSE;
		else if(ret > 0)
			return RECV_USER_ERROR;
		else
			return RECV_SOCKET_ERROR;
	}
};

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -