简单易用的 IOCP 服务器框架






3.43/5 (8投票s)
SPServer 框架介绍
1. 引言
SPServer 是一个基于 Windows IOCP 的简单易用的服务器框架库。 它包括一个基本的 TCP 服务器框架和一个简单的 HTTP 服务器框架。它内置支持类似聊天室的应用程序。 SPServer 可以简化 TCP 服务器的构建。
2. 背景
IOCP 很好,但是当我们使用 IOCP 来实现一个稳定的服务器时,我们仍然需要做一些复杂的事情。 通常,我们需要处理以下事情:
- 处理部分读取,我们需要进行多次
WSARecv
才能读取完整的请求消息。 - 处理部分写入,我们需要进行多次
WSASend
才能写入完整的响应消息。 - 如果我们想实现一个类似聊天室的应用程序,我们需要同时处理多个套接字。 如果我们使用线程池来运行 IOCP,我们需要仔细处理这种情况。
SPServer 是一个尝试封装上述复杂问题的框架,并为应用程序员提供一个简单易用的接口。
3. 使用代码
下面描述了一个简单的行回显服务器。 这个回显服务器与一般的回显服务器不同:它在读取到行终止符 -- CRLF 之前不会响应。
这个示例展示了框架的基本概念。 要使用这个框架,你需要实现一个应用程序指定的处理器和处理器工厂。
如果也使用 CRLF 作为请求消息的分隔符,可以重用 SP_LineMsgDecoder
;否则,你需要实现一个应用程序指定的消息解码器。
class SP_LineMsgDecoder : public SP_MsgDecoder {
public:
virtual int decode( SP_Buffer * inBuffer );
const char * getMsg();
};
class SP_EchoHandler : public SP_Handler {
public:
// return -1 : terminate session, 0 : continue
virtual int start( SP_Request * request, SP_Response * response ) {
request->setMsgDecoder( new SP_LineMsgDecoder() );
response->getReply()->getMsg()->append(
"Welcome to line echo server, enter 'quit' to quit.\r\n" );
return 0;
}
// return -1 : terminate session, 0 : continue
virtual int handle( SP_Request * request, SP_Response * response ) {
SP_LineMsgDecoder * decoder = (SP_LineMsgDecoder*)request->getMsgDecoder();
if( 0 != strcasecmp( (char*)decoder->getMsg(), "quit" ) ) {
response->getReply()->getMsg()->append( (char*)decoder->getMsg() );
response->getReply()->getMsg()->append( "\r\n" );
return 0;
} else {
response->getReply()->getMsg()->append( "Byebye\r\n" );
return -1;
}
}
};
class SP_EchoHandlerFactory : public SP_HandlerFactory {
public:
virtual SP_Handler * create() const {
return new SP_EchoHandler();
}
};
int main( int argc, char * argv[] )
{
const char * host = "127.0.0.1";
int port = 3333;
SP_IocpServer server( host, port, new SP_EchoHandlerFactory() );
server.runForever();
return 0;
}
4. 类接口
行回显服务器引用了一些类
SP_MsgDecoder
SP_Request
SP_Message
SP_Response
SP_Buffer
SP_Handler
4.1 SP_MsgDecoder 和 SP_Request
class SP_MsgDecoder {
public:
enum { eOK, eMoreData };
virtual int decode( SP_Buffer * inBuffer ) = 0;
};
/* act as the SP_MsgDecoder's container */
class SP_Request {
public:
SP_MsgDecoder * getMsgDecoder();
void setMsgDecoder( SP_MsgDecoder * decoder );
};
4.2 SP_Message 和 SP_Response
typedef struct tagSP_Sid SP_Sid_t;
class SP_SidList {
public:
int getCount() const;
void add( SP_Sid_t sid );
SP_Sid_t get( int index ) const;
SP_Sid_t take( int index );
int find( SP_Sid_t sid ) const;
};
class SP_Message {
public:
SP_SidList * getToList();
SP_Buffer * getMsg();
};
/* act as the SP_Message's container */
class SP_Response {
public:
SP_Message * getReply();
void addMessage( SP_Message * msg );
SP_Message * peekMessage();
SP_Message * takeMessage();
};
4.3 SP_Handler 和 SP_Buffer
class SP_Handler {
public:
// return -1 : terminate session, 0 : continue
virtual int start( SP_Request * request, SP_Response * response ) = 0;
// return -1 : terminate session, 0 : continue
virtual int handle( SP_Request * request, SP_Response * response ) = 0;
virtual void error( SP_Response * response ) = 0;
virtual void timeout( SP_Response * response ) = 0;
virtual void close() = 0;
};
class SP_Buffer {
public:
int append( const void * buffer, int len = 0 );
int append( const SP_Buffer * buffer );
void erase( int len );
void reset();
const void * getBuffer() const;
size_t getSize() const;
int take( char * buffer, int len );
char * getLine();
const void * find( const void * key, size_t len );
SP_Buffer * take();
};
5. 框架的关键流程
5.1 处理部分读取
行回显服务器使用 SP_LineMsgDecoder
来处理部分读取。 SP_LineMsgDecoder
是 SP_MsgDecoder
的子类。
框架的处理步骤如下:
- 当框架接受一个客户端时,它调用
SP_Handler::start
,我们可以在此时创建应用程序指定的MsgDecoder
--SP_LineMsgDecoder
。 - 框架为套接字发出
WSARecv
。 - 当框架从套接字读取一些数据时,它调用
SP_MsgDecoder::decode
方法。 - 如果
inBuffer
中保存的数据代表一个完整的请求消息,则它返回SP_MsgDecoder::eOK
并转到第 5 步,否则它返回SP_MsgDecoder::eMoreData
并转到第 2 步。 - 将数据复制到你自己的缓冲区,然后从
inBuffer
中擦除数据。 - 框架调用
SP_Handler::handle
方法。 我们可以检索SP_LineMsgDecoder
,并从SP_LineMsgDecoder
获取请求消息。
5.2 处理部分写入
框架使用 SP_Response
和 SP_Message
来处理部分写入。 SP_Response
是 SP_Message
的容器。 SP_Message
用于保存响应消息。
框架的处理步骤如下:
- 框架调用
SP_Handler::handle
方法。 请求消息被处理,然后生成响应消息。 响应消息被附加到SP_Response
。 - 框架为套接字发出
WSASend
。 - 当
WSASend
完成时,框架检查TransferredBytes
,如果仍然有一些数据要发送,则转到第 2 步。
5.3 内置支持类似聊天室的应用程序
当客户端连接时,框架为每个客户端分配一个 uuid
。 当我们生成响应时,我们可以通过将客户端的 uuid
添加到 SP_Message::mToList
来向客户端发送响应消息。 该框架封装了同时为多个套接字发送响应消息的复杂性。
在源代码包中有一个聊天室演示 -- testiocpdispatcher.cpp。 更多详细信息,请参考本文顶部提供的源代码。
6. 其他
SPServer 的核心部分在 Windows 平台上是独立的,它不依赖于任何第三方库。 因此,你可以仅使用 Visual Studio (VC++6 或更高版本) 构建库和演示程序。
SPServer 实现了一个插件机制来支持 SSL 通信。 如果你需要使用 SSL,你必须安装 OpenSSL 或 XySSL。
7. 参考文献
- 项目主页:spserver
- 下载:spserver-0.9.2.src.tar.gz
8. 历史
- 2008-06-28:第一个版本