cif包含目的港费用吗结目的sp-gift所有页面,现在以wwWsp-giftcom无法在显示了

A Parting Gift-Bl_nk Sp_c_s, A Parting GiftMP3下载,歌词下载 - 虾米音乐
Loading...
A Parting Gift
@微博好友,送歌给Ta!
Sorry,此歌曲暂无文本歌词。
使用手机扫码收听单曲
打开虾米音乐APP
点击 扫一扫
扫描二维码
收藏A Parting Gift的人们
听A Parting Gift的人也听
关注虾米:博客分类:
spserver 是一个实现了半同步/半异步(Half-Sync/Half-Async)和领导者/追随者(Leader/Follower) 模式的服务器框架,能够简化 TCP server 的开发工作。
spserver 使用 c++ 实现,目前实现了以下功能:
1.封装了 TCP server 中接受连接的功能;
2.使用非阻塞型I/O和事件驱动模型,由主线程负责处理所有 TCP 连接上的数据读取和发送,因此连接数不受线程数的限制;
3.主线程读取到的数据放入队列,由一个线程池处理实际的业务。
4.一个 http 服务器框架,即嵌入式 web 服务器(请参考:)
0.6 版本之前只包含 Half-Sync/Half-Async 模式的实现,0.6 版本开始包含 Leader/Follower 模式的实现
0.7 版本开始支持 ssl 。把 socket 相关的操作抽象为一个 IOChannel 层,关于 openssl 的部分单独实现为一个 plugin 的形式,对于不使用 ssl 功能的用户,不需要引入 ssl 相关的头文件和库。
0.7.5 增加了一个 sptunnel 程序,是一个通用的 ssl proxy 。类似 stunnel 。
0.9.0 移植 spserver 到 windows 平台,需要在 windows 下编译 libevent 和 pthread 。
0.9.1 在 windows 平台,去掉了对 libevent 和 pthread 依赖,完全使用 iocp 和 windows 的线程机制实现了半同步半异步的框架。
0.9.2 移植了所有的功能到 windows 平台,同时新增加了 xyssl 的插件。
源代码下载:
在实现并发处理多事件的应用程序方面,有如下两种常见的编程模型:
ThreadPerConnection的多线程模型和事件驱动的单线程模型。
ThreadPerConnection的多线程模型
优点:简单易用,效率也不错。在这种模型中,开发者使用同步操作来编写程序,比如使用阻塞型I/O。使用同步操作的程序能够隐式地在线程的运行堆栈中维护应用程序的状态信息和执行历史,方便程序的开发。
缺点:没有足够的扩展性。如果应用程序只需处理少量的并发连接,那么对应地创建相应数量的线程,一般的机器都还能胜任;但如果应用程序需要处理成千上万个连接,那么为每个连接创建一个线程也许是不可行的。
事件驱动的单线程模型
优点:扩展性高,通常性能也比较好。在这种模型中,把会导致阻塞的操作转化为一个异步操作,主线程负责发起这个异步操作,并处理这个异步操作的结果。由于所有阻塞的操作都转化为异步操作,理论上主线程的大部分时间都是在处理实际的计算任务,少了多线程的调度时间,所以这种模型的性能通常会比较好。
缺点:要把所有会导致阻塞的操作转化为异步操作。一个是带来编程上的复杂度,异步操作需要由开发者来显示地管理应用程序的状态信息和执行历史。第二个是目前很多广泛使用的函数库都很难转为用异步操作来实现,即是可以用异步操作来实现,也将进一步增加编程的复杂度。
并发系统通常既包含异步处理服务,又包含同步处理服务。系统程序员有充分的理由使用异步特性改善性能。相反,应用程序员也有充分的理由使用同步处理简化他们的编程强度。
针对这种情况,ACE 的作者提出了 半同步/半异步 (Half-Sync/Half-Async) 模式。
引用
上对这个模式的描述如下:
半同步/半异步 体系结构模式将并发系统中的异步和同步服务处理分离,简化了编程,同时又没有降低性能。该模式介绍了两个通信层,一个用于异步服务处理,另一个用于同步服务处理。
目标:
需要同步处理的简易性的应用程序开发者无需考虑异步的复杂性。同时,必须将性能最大化的系统开发者不需要考虑同步处理的低效性。让同步和异步处理服务能够相互通信,而不会使它们的编程模型复杂化或者过度地降低它们的性能。
解决方案:
将系统中的服务分解成两层,同步和异步,并且在它们之间增加一个排队层协调异步和同步层中的服务之间的通信。在独立线程或进程中同步地处理高层服务(如耗时长的数据库查询或文件传输),从而简化并发编程。相反,异步地处理底层服务(如从网络连接上读取数据),以增强性能。如果驻留在相互独立的同步和异步层中的服务必须相互通信或同步它们的处理,则应允许它们通过一个排队层向对方传递消息。
模式原文:Half-Sync/Half-Async: An Architectural Pattern for Efficient and Well-structured Concurrent I/O
中文翻译:
如果上面关于 半同步/半异步 的说明过于抽象,那么可以看一个《POSA2》中提到的例子:
许多餐厅使用 半同步/半异步 模式的变体。例如,餐厅常常雇佣一个领班负责迎接顾客,并在餐厅繁忙时留意给顾客安排桌位,为等待就餐的顾客按序排队是必要的。领班由所有顾客“共享”,不能被任何特定顾客占用太多时间。当顾客在一张桌子入坐后,有一个侍应生专门为这张桌子服务。
下面来看一个使用 spserver 实现的简单的 line echo server 。
class SP_EchoHandler : public SP_Handler {
SP_EchoHandler(){}
virtual ~SP_EchoHandler(){}
// 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 -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" );
response-&getReply()-&getMsg()-&append( "Byebye\r\n" );
return -1;
virtual void error( SP_Response * response ) {}
virtual void timeout( SP_Response * response ) {}
virtual void close() {}
class SP_EchoHandlerFactory : public SP_HandlerFactory {
SP_EchoHandlerFactory() {}
virtual ~SP_EchoHandlerFactory() {}
virtual SP_Handler * create() const {
return new SP_EchoHandler();
int main( int argc, char * argv[] )
int port = 3333;
SP_Server server( "", port, new SP_EchoHandlerFactory() );
server.runForever();
在最简单的情况下,使用 spserver 实现一个 TCP server 需要实现两个类:SP_Handler 的子类 和 SP_HandlerFactory 的子类。
SP_Handler 的子类负责处理具体业务。
SP_HandlerFactory 的子类协助 spserver 为每一个连接创建一个 SP_Handler 子类实例。
1.SP_Handler 生命周期
SP_Handler 和 TCP 连接一对一,SP_Handler 的生存周期和 TCP 连接一样。
当 TCP 连接被接受之后,SP_Handler 被创建,当 TCP 连接断开之后,SP_Handler将被 destroy。
2.SP_Handler 函数说明
SP_Handler 有 5 个纯虚方法需要由子类来重载。这 5 个方法分别是:
start:当一个连接成功接受之后,将首先被调用。返回 0 表示继续,-1 表示结束连接。
handle:当一个请求包接收完之后,将被调用。返回 0 表示继续,-1 表示结束连接。
error:当在一个连接上读取或者发送数据出错时,将被调用。error 之后,连接将被关闭。
timeout:当一个连接在约定的时间内没有发生可读或者可写事件,将被调用。timeout 之后,连接将被关闭。
close:当一个 TCP 连接被关闭时,无论是正常关闭,还是因为 error/timeout 而关闭。
3.SP_Handler 函数调用时机
当需要调用 SP_Handler 的 start/handle/error/timeout 方法时,相关的参数将被放入队列,然后由线程池来负责执行 SP_Handler 对应的方法。因此在 start/handle/error/timeout 中可以使用同步操作来编程,可以直接使用阻塞型 I/O 。
在发生 error 和 timeout 事件之后,close 紧跟着这两个方法之后被调用。
如果是程序正常指示结束连接,那么在主线程中直接调用 close 方法。
4.高级功能--MsgDecoder
这个 line echo server 比起常见的 echo server 有一点不同:只有在读到一行时才进行 echo。
这个功能是通过一个称为 MsgDecoder 的接口来实现的。不同的 TCP server 在应用层的传输格式上各不相同。
比如在 SMTP/POP 这一类的协议中,大部分命令是使用 CRLF 作为分隔符的。而在 HTTP 中是使用 Header + Body 的形式。
为了适应不同的 TCP server,在 spserver 中有一个 MsgDecoder 接口,用来处理这些应用层的协议。
比如在这个 line echo server 中,把传输协议定义为:只有读到一行时将进行 echo 。
那么相应地就要实现一个 SP_LineMsgDecoder ,这个 LineMsgDecoder 负责判断目前的输入缓冲区中是否已经有完整的一行。
MsgDecoder 的接口如下:
class SP_MsgDecoder {
virtual ~SP_MsgDecoder();
enum { eOK, eMoreData };
virtual int decode( SP_Buffer * inBuffer ) = 0;
decode 方法对 inBuffer 里面的数据进行检查,看是否符合特定的要求。如果已经符合要求,那么返回 eOK ;如果还不满足要求,那么返回 eMoreData。比如 LineMsgDecoder 的 decode 方法的实现为:
int SP_LineMsgDecoder :: decode( SP_Buffer * inBuffer )
if( NULL != mLine ) free( mLine );
mLine = inBuffer-&getLine();
return NULL == mLine ? eMoreData : eOK;
spserver 默认提供了几个 MsgDecoder 的实现:
SP_DefaultMsgDecoder :它的 decode 总是返回 eOK ,即只要有输入就当作是符合要求了。
&&& 如果应用不设置 SP_Request-&setMsgDecoder 的话,默认使用这个。
SP_LineMsgDecoder : 检查到有一行的时候,返回 eOK ,按行读取输入。
SP_DotTermMsgDecoder :检查到输入中包含了特定的 &CRLF&.&CRLF& 时,返回 eOK。
具体的使用例子可以参考示例:testsmtp 。
5.高级功能--实现聊天室
spserver 还提供了一个广播消息的功能。使用消息广播功能可以方便地实现类似聊天室的功能。具体的实现可以参考示例:testchat 。
6.libevent
spserver 使用 c++ 实现,使用了一个第三方库--libevent,以便在不同的平台上都能够使用最有效的事件驱动机制(Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and epoll(4). )。
浏览 66205
论坛回复 /
(55 / 54161)
好像没看到调用event_base_free,是不是因为没办法取消所有注册的event? 我刚好也遇到这个问题,总是不能很好地处理退出。SPServer内部保存了所有注册的 struct event,可以取消所有注册的 event 的。不过 libevent 1.1 和 1.2 中有 bug ,在 event_init 的时候,libevent 自身注册了一些 event ,这些 event 在 event_base_free 的时候,没有取消,导致 event_base_free 会被挂住。另外 event_base_free 是从 1.2 开始才有的,1.1 都没有 event_base_free ,所以目前在 SPServer 中都把 event_base_free 调用注释掉了。
在这里重新分配了内存,有没有更好的办法?
想到了一个方法,就是为 SP_Buffer 增加一个 take 的方法,如下
class SP_Buffer {
SP_Buffer * take();
通过这个方法,可以直接把 SP_Buffer 底层控制的内存块拿出来用,同时 SP_Buffer 自身重新分配控制块。这个控制块很小,大概只有 50 bytes 。这样可以减少内存的复制操作。
使用的例子可以参考 spserver/openssl/sptunnelimpl.cpp 文件中的
int SP_TunnelDecoder :: decode( SP_Buffer * inBuffer ) 函数。
int SP_DotTermMsgDecoder :: decode( SP_Buffer * inBuffer )
if( NULL != mBuffer ) free( mBuffer );
const char * pos = (char*)inBuffer-&find( "\r\n.\r\n", 5 );
if( NULL == pos ) {
pos = (char*)inBuffer-&find( "\n.\n", 3 );
if( NULL != pos ) {
int len = pos - (char*)inBuffer-&getBuffer();
mBuffer = (char*)malloc( len + 1 );
memcpy( mBuffer, inBuffer-&getBuffer(), len );
mBuffer[ len ] = '\0';
inBuffer-&erase( len );
在这里重新分配了内存,有没有更好的办法?
还是就是如果有两个数据包同时被接收,后面一个包怎么处理?
不知道我说的对不对,还有几个问题想要请救,方便留个MSN?
我的是
对于一个 fd,如果有两个数据包同时被读入 inBuffer 里面,后面的数据包将在前一个数据包被处理完之后,继续被处理。这两个数据包不会被并行处理,因为 SP_Handler 和 fd 是一一对应的,如果并行处理数据包,将导致 SP_Handler 可能同时被多个线程调用,这样将使得 SP_Handler 非常难于实现。
关于重新分配内存的问题:inBuffer 是使用 read 系统调用从 fd 里面读入的。使用 read 的时候,是尽可能地读入数据,因此 inBuffer 里面的数据就不一定是逻辑上的一个数据包。由于 inBuffer 里面的数据不一定正好是一个逻辑上的数据包,也有可能多于一个逻辑上的数据包,而为了能够提供给应用层(SP_Handler::handle)方便地使用,因此不得不做了一次数据 copy 。如果 inBuffer 里面的数据不需要做逻辑上的 decode 操作,那么这次 copy 的确有浪费之嫌。如果 inBuffer 里面的数据需要经过 decode 操作(比如解压缩,解密,或者协议解释),那么这次 copy 操作就是无法避免的了。比如 http msg decoder 的实现
int SP_HttpRequestDecoder :: decode( SP_Buffer * inBuffer )
if( inBuffer-&getSize() & 0 ) {
int len = mParser-&append( inBuffer-&getBuffer(), inBuffer-&getSize() );
inBuffer-&erase( len );
return mParser-&isCompleted() ? eOK : eMoreD
return eMoreD
另外有一点,上面的 decode( SP_Buffer * inBuffer ) 的实现是用一种最简单,但内存使用最多的方式来实现的。其实可以在 else 中把 inBuffer 复制到 mBuffer 中,不过前面的判断是否已经完整读取到一个数据包的逻辑就变得比较复杂了。这样可以避免把内容一直放在 inBuffer 。
int SP_DotTermMsgDecoder :: decode( SP_Buffer * inBuffer )
。。。。。。
if( NULL != pos ) {
// 复制 inBuffer 的内容到 mBuffer,同时清空 inBuffer
说到这里,可能就是一个关于 SPServer 适用范围的问题了,如果多出来的这次 copy 操作是无法接受的,那么可能就需要另外的专门的解决方案了。
关于 SP_MsgDecoder 的设计思路,当初主要是模仿 java 的 mina 框架。mina 框架号称
引用
如果想实现复杂的如LDAP这样的协议怎么办呢?它似乎是一个恶梦,因为IO层没有帮助你分离‘message解析’和‘实际的业务逻辑(比如访问一个目录数据库)’。MINA提供了一个协议层来解决这个问题。协议层将ByteBuffer事件转换成高层的POJO事件:
就像前面提到的,你只需撰写面向POJO的message而不是ByteBuffer的。ProtocolEncoder 将message对象解释成ByteBuffers以便IO层能够将他们输出到socket。
是指解决什么问题?是说 SP_MsgDecoder 实现的时候,缓冲有问题?
int SP_DotTermMsgDecoder :: decode( SP_Buffer * inBuffer )
{
if( NULL != mBuffer ) free( mBuffer );
const char * pos = (char*)inBuffer-&find( "\r\n.\r\n", 5 );
if( NULL == pos ) {
pos = (char*)inBuffer-&find( "\n.\n", 3 );
if( NULL != pos ) {
int len = pos - (char*)inBuffer-&getBuffer();
mBuffer = (char*)malloc( len + 1 );
memcpy( mBuffer, inBuffer-&getBuffer(), len );
mBuffer[ len ] = '\0';
inBuffer-&erase( len );
在这里重新分配了内存,有没有更好的办法?
还是就是如果有两个数据包同时被接收,后面一个包怎么处理?
不知道我说的对不对,还有几个问题想要请救,方便留个MSN?
我的是
SP_MsgDecoder 实现时,COPY缓冲能不能很好的解决?
是指解决什么问题?是说 SP_MsgDecoder 实现的时候,缓冲有问题?
底层无论是使用select还是epoll,都无法在不加锁的情况下,在一个原子操作中完成取出事件并取消已经注册的事件。
经过测试,我这个说法是错误的。epoll有个EPOLLONESHOT可以完成一次性事件,可以让epoll_wait每次只取一个事件,从而达到没有线程锁的情况下实现LF模式。一个线程调用epoll_wait时还允许其它线程调用epoll_ctl来注册事件。多个线程在同一个epoll描述符上执行epoll_wait内核会进行排队,不会出现一个事件在有EPOLLONESHOT时还被多个线程得到的情况,所以可以在无锁的情况下完成整个过程,目前简单测试通过了。
有没有测试多CPU?结果可能会不同吧。测试的主要关键点是在测试案例的选取上。就目前这个 testhttp.cpp 的案例来说,多 CPU 对性能的提升应该不大了。对于这种案例,如果要在多 CPU 上获得更好的性能,应该使用 memcached 的方法,每个线程使用一个 event_base 。引用底层无论是使用select还是epoll,都无法在不加锁的情况下在
书中,多次提到 win32 WaitForMultiObjects 函数允许线程池在同一个句柄集上同时等待来支持并发句柄集。引用可能还是要自己去整底层API,依赖libevent可能还是有局限性对于 event-driven 编程方式的封装,libevent 其实做得很好了。libevent 主要的特点是使用 callback ,但这个也是由 event-driven 决定的。这种实现方式就相当于设计模式中的“被动迭代器”。通过上面提到的方法可以把“被动迭代器”转换为“主动迭代器”。引用为了把 reactor/proactor 和线程池分开,可以用一个间接的方法。在 callback 中不直接处理事件,把事件保存到一个列表(eventList)里面,这样就可以使得 event_loop 要做的事情很简单。等到 event_loop 运行完之后,就可以使用相应的线程池策略来处理 eventList 了。如果要改进,应该就是要考虑如何一步到位地把 event-driven 编程方式封装为“主动迭代器”的方式。
为了把 reactor/proactor 和线程池分开,可以用一个间接的方法。在 callback 中不直接处理事件,把事件保存到一个列表(eventList)里面,这样就可以使得 event_loop 要做的事情很简单。等到 event_loop 运行完之后,就可以使用相应的线程池策略来处理 eventList 了。
从目前想象到的运行过程来看,LF 的线程切换应该比 HAHS 少很多,性能应该会更好。
今天试着用这个思路来实现 Leader/Follower ,为 SPServer 增加了一个 SP_LFServer 的类,接口和 SP_Server 一样。
然后修改了
的代码,使得可以在命令行指定使用的线程池模型,然后用 ab 做了一些简单的测试。
testhttp.cpp 的功能很简单,只是把收到的 http 请求解释出来,然后把解释到的内容作为 response 返回给客户端。由于 testhttp.cpp 的功能足够简单,所以用来测试线程的切换的消耗还是比较理想的。
从初步的测试结果来看,在 testhttp.cpp 这种应用中, LF 比 HAHS 快。
测试不是很严格,针对 HAHS 和 LF 分别测试使用 1 个线程和 2 个线程的情况,每个 case 运行 5 次,取中间的结果。性能最好的是 LF 使用 1 个线程的时候,因为这里完全没有线程的切换, 。
得到的数据,LF 使用 1 线程的时候,处理请求的速度和 memcached 差不多。memcached 是单线程的。
对于 HAHS 模型的测试结果
bash-2.05a$ ./testhttp -s hahs -t 1
bash-2.05a$ ./ab -n 10000 -c 100 -k http://127.0.0.1:8080/
Requests per second:
3464.96 [#/sec] (mean)
bash-2.05a$ ./testhttp -s hahs -t 2
bash-2.05a$ ./ab -n 10000 -c 100 -k http://127.0.0.1:8080/
Requests per second:
2768.06 [#/sec] (mean)
对于 LF 模型的测试结果
bash-2.05a$ ./testhttp -s lf -t 1
bash-2.05a$ ./ab -n 10000 -c 100 -k http://127.0.0.1:8080/
Requests per second:
4576.40 [#/sec] (mean)
bash-2.05a$ ./testhttp -s lf -t 2
bash-2.05a$ ./ab -n 10000 -c 100 -k http://127.0.0.1:8080/
Requests per second:
2951.07 [#/sec] (mean)
LF线程切换会比HAHS少?目前你的HAHS实现是怎样的?我是做了一个同步队列,所以这个线池里面的线程是阻塞在同步队列上的,这些线程的关系应该也是LF。
目前是实现了一个 Executor ,这个 Executor 对象是一个主动对象,内部维持一个任务队列和一个线程池( worker )。创建 Executor 对象的时候,自动会创建一个线程(称为 scheduler 线程 ),这个线程复杂分派队列中的任务给线程池中的线程。
Executor 的使用场景类似这样:
void main_thread( .... )
for( ; ; ) {
Task * task =
executor.execute( task );
这样带来的好处是 Executor 可以用 lazy 的方式来创建线程池里面的线程,也可以在必要的时候回收线程。
另外就是使用者容易使用,接口容易理解。这种线程池的使用和普通的 connection pool 之类的池很类似。
过量的任务只会阻塞 scheduler ,不会阻塞 main_thread 。
坏处就是多了线程的切换。executor.execute 的时候,从 main_thread 切换到 scheduler 线程,然后 scheduler 线程分派任务,又从 scheduler 切换到 worker 线程。
引用另一个LF方式的缺点,就是各个处理线程都忙时,不会再接受连接,而HAHS方式是先接下来再说,接下来的连接还可以先接收数据,至于哪种方式更合理,我也不能确定。
LF 的确有这种问题。所以可能要做到由用户来选择,把 HAHS 和 LF 封装起来,可以方便地切换。
现在最不自然的地方,就是Protocol来处理是否放入线程池,因为read请求也是它发起的,问题在于线程池在reactor里面,所以现在是通过protocol找到factory再找到reactor,虽然直接用指针就定位到了(factory-&reactor-&addTask(this)),不过感觉很不舒服。这类问题在twisted和ace里面可能是使用全局变量或singleton来访问,但我想在一个系统里面同时跑起多个reactor(虽然不一定有用),更重要的原因是我极度讨厌全局变量和singleton。
使用 libevent 和线程池,一般很自然地就把线程池和 reactor 混在一起了。
主要的原因是 libevent 的 event_loop 的实现,当底层的 select/poll/epoll 探测到有事件的时候,event_loop 是逐个处理所有的事件,在 event_loop 内部调用所有的 callback 。而一般就是在 callback 里面直接处理事件了。
为了把 reactor/proactor 和线程池分开,可以用一个间接的方法。在 callback 中不直接处理事件,把事件保存到一个列表(eventList)里面,这样就可以使得 event_loop 要做的事情很简单。等到 event_loop 运行完之后,就可以使用相应的线程池策略来处理 eventList 了。
在这里有类似的描述
代码大概是这样的
class Reactor {
int handle_events() {
if( mEventList-&getCount() &= 0 ) {
// 把所有的 event 保存到 mEventList 中
event_loop( xxx );
Event * event = mEventList-&remove( 0 );
if( NULL != event ) {
// process event
List * mEventL
int main( ... )
// 可以使用不同的线程池模型来处理这个循环
// 可以是 Half-Async/Half-Sync ,也可以是 Leader/Follower
for( ; ; ) {
reactor.handle_events();
我也正准备按这个思路来尝试修改 spserver ,然后对比一下 HAHS 和 LF 线程池模型的性能差异。
从目前想象到的运行过程来看,LF 的线程切换应该比 HAHS 少很多,性能应该会更好。
关键的地方是
引用 (Please, see Collections of results below how to avoid/minimize the cost of operations on collections).
对于HTTP这种没有长度前缀的,最好还是用reactor方式,当然用上面的proactor方式也是可以的对于不是使用真正的异步 IO (*nix aio 或者 win iocp) 实现的 proactor ,其实都可以认为是用 reactor 模拟出来的。用 reactor 模拟 proactor ,在这篇文章中描述得很清楚在不使用真正的异步 IO 的情况下,reactor 还是 proactor ,差别只在于曝露出来的 handler 接口。reactor 的接口体现的是 IO 句柄上发生了事件。(在 POSA2 的 page114)
class Event_Handler {
virtual void handle_input( HANDLE handle ) = 0;
virtual void handle_output( HANDLE handle ) = 0;
virtual void handle_timeout( const Time_Value & ) = 0;
virtual void handle_close( HANDLE handle, Event_Type et ) = 0;
proactor 的接口体现的是 IO 读写事件已经完成了。(在 POSA2 的 page139)
class Completion_Handler {
virtual void handle_read( HANDLE handle, const Async_Result &result ) = 0;
virtual void handle_write( HANDLE handle, const Async_Result &result ) = 0;
用 reactor 模拟 proactor ,就是设计一个 Event_Handler 的子类,设计一套 Async_Result ,把 Event_Handler 接口适配为 Completion_Handler 。在 SPServer 的设计中,SP_EventCallback 可以看成是这个适配子类,SP_MsgDecoder 可以看成是 read 的 Async_Result,SP_Message 可以看成是 write 的 Async_Result 。引用对于HTTP这种没有长度前缀的,最好还是用reactor方式,当然用上面的proactor方式也是可以的,因为有上readall参数可以设置为 false。好像和原来的reactor又兼容得不好了,我想是不是可以在收到数据后判断是否有读请求,如果没有则直接调用dataReceived。不过感觉和requestRead这种请求/回调的思想不一致。也不想再维护一个单线程的reactor、一个多线程reactor和一个多线程的 proactor。对于 HTTP 这种协议,如果直接使用 blocking TCP socket 的话,很容易实现。但无论是使用 reactor 还是 proactor ,都是为了避免 blocking TCP socket ,因此就不可避免需要实现一个面向流的 http message parser 了。有了这个面向流的 http message parser ,那么无论使用何种接口,都可以容易地实现功能了。不是很明白这里 qiezi 提到的 “和原来的reactor又兼容得不好了”的意思。PS:qiezi 是使用 D 语言在实现吧?不知道有没有计划 open 这个实现?
& 上一页 1
浏览: 326016 次
写道我理解下来,之所以使用奇数应该不仅仅是 ...
我理解下来,之所以使用奇数应该不仅仅是为了判断谁赢。而是这样就 ...
you are my hero! 看了你的图示之后,我的理解是 ...
相当好!通俗易懂,看了好几篇paxos只有你这个最深入浅出!
tangfu 写道hi,问一下,博主提供的库与pb兼容么,比如 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 1111sp页面访问升级 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信