SPServer: 一个基于线程池(包括HAHS和LF)的开源服务器框架

时间:2008-01-16 11:14:26  来源:  作者:

SPServer 是一个实现了半同步/半异步(Half-Sync/Half-Async)和领导者/追随者(Leader/Follower) 模式的服务器框架,能够简化 TCP server 的开发工作。

SPServer 使用 c++ 实现,目前实现了以下功能:
1.封装了 TCP server 中接受连接的功能;
2.使用非阻塞型I/O和事件驱动模型,基于 libevent;
3.对于 HSHA 线程池,由主线程负责处理所有 TCP 连接上的数据读取和发送,因此连接数不受线程数的限制;主线程读取到的数据放入队列,由一个线程池处理实际的业务;
4.对于 LF 线程池,由线程池中的线程轮流获得 leader 角色进行处理;
5.一个 http 服务器框架,即嵌入式 web 服务器。
6.从 0.7 版本开始支持 ssl 。

项目主页
[url=http://code.google.com/p/spserver/]http://code.google.com/p/spserver/

下载地址
[url=http://freshmeat.net/redir/spserver/68862/url_tgz/spserver-0.3.src.tar.gz]http://spserver.googlecode.com/files/spserver-0.6.src.tar.gz 
[url=http://code.google.com/p/spserver/downloads/list]http://code.google.com/p/spserver/downloads/list

详细的介绍
[url=http://iunknown.javaeye.com/blog/59804]http://iunknown.javaeye.com/blog/59804

HSHA 模式
[url=http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf]http://www.cs.wustl.edu/~schmidt/PDF/HS-HA.pdf

LF 模式
[url=http://www.cs.wustl.edu/~schmidt/PDF/lf.pdf]http://www.cs.wustl.edu/~schmidt/PDF/lf.pdf

关于 HSHA 和 LF 的一些介绍
[url=http://iunknown.javaeye.com/blog/60414]http://iunknown.javaeye.com/blog/60414

项目中包含一个线程池子项目
http://iunknown.javaeye.com/blog/38544 

[ 本帖最后由 iunknown 于 2007-8-11 13:36 编辑 ]



 converse 回复于:2007-07-04 20:32:49

小声的说,LZ的博客在我家FF的链接中保存着....


 iunknown 回复于:2007-07-05 13:20:16

引用:原帖由 converse 于 2007-7-4 20:32 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7006900&ptid=957813]
小声的说,LZ的博客在我家FF的链接中保存着.... 



多谢!你这样说,我很大压力啊。。。。。:) 

关于 HSHA , LF 线程池,还有 reactor ,proactor 这些模式,目前能找到的参考实现有 ACE 和 twisted 。
不知这里有没有人做过类似的框架?或者有没有人希望使用这样的框架?希望能获得大家的建议,继续完善。

[ 本帖最后由 iunknown 于 2007-7-5 13:21 编辑 ]


 iunknown 回复于:2007-07-06 13:48:32

在 [url=http://code.google.com/p/spserver/]SPServer 中实现了 HSHA 和 LF 两种线程池。

目前的实现还是比较可读的,这两种线程池最主要的处理逻辑各自都被集中到了一个函数中。

先来看看 HSHA 的核心实现代码

http://spserver.googlecode.com/svn/trunk/spserver.cpp


int SP_Server :: start()
{
......

SP_Executor workerExecutor( mMaxThreads, "work" );
SP_Executor actExecutor( 1, "act" );

/* Start the event loop. */
while( 0 == mIsShutdown ) {
event_base_loop( eventArg.getEventBase(), EVLOOP_ONCE );

for( ; NULL != eventArg.getInputResultQueue()->top(); ) {
SP_Task * task = (SP_Task*)eventArg.getInputResultQueue()->pop();
workerExecutor.execute( task );
}

for( ; NULL != eventArg.getOutputResultQueue()->top(); ) {
SP_Message * msg = (SP_Message*)eventArg.getOutputResultQueue()->pop();

......

actExecutor.execute( outputCompleted, arg );
}
}

......
}


一些细节都被去掉了。从这段代码可以看到,HSHA 的处理流程是:
1.运行 start 函数的线程称为 event_loop 线程,负责 recv/send 。
  所有的 recv/send 都在 event_base_loop 这个函数调用上完成的。
  这个层就是属于异步层。
2. event_base_loop 在 recv 的时候,会调用 MsgDecoder.decode 函数,
  如果 decode 返回 OK ,说明完整地读入数据了,那么就把对应的数据放入 
  eventArg.mInputResultQueue 里面。
  在 send 的时候,如果把一个 Message 完整地发送了,
  那么就把这个 Message 放入 eventArg.mOutputResultQueue。
  这两个就是队列,队列里面保存的数据一般称为完成事件。
3.workerExecutor 和 actExecutor 就是同步层。
  由于完成事件的处理可能会涉及很复杂的处理,可能会使用到数据库或者其他,
  因此不能直接使用 event_loop 线程,而是使用线程池。
  这个就是同步层。

再来看 LF 的核心代码

http://spserver.googlecode.com/svn/trunk/splfserver.cpp


int SP_LFServer :: run()
{
......
mThreadPool = new SP_ThreadPool( mMaxThreads );
for( int i = 0; i < mMaxThreads; i++ ) {
mThreadPool->dispatch( lfHandler, this );
}
......
}

void SP_LFServer :: lfHandler( void * arg )
{
SP_LFServer * server = (SP_LFServer*)arg;

for( ; 0 == server->mIsShutdown; ) {
/* follower begin */
server->handleOneEvent();
}
}

void SP_LFServer :: handleOneEvent()
{
SP_Task * task = NULL;
SP_Message * msg = NULL;

/* follower wait */

pthread_mutex_lock( &mMutex );

/* follower end */

/* leader begin */

for( ; 0 == mIsShutdown && NULL == task && NULL == msg; ) {
if( mEventArg->getInputResultQueue()->getLength() > 0 ) {
task = (SP_Task*)mEventArg->getInputResultQueue()->pop();
} else if( mEventArg->getOutputResultQueue()->getLength() > 0 ) {
msg = (SP_Message*)mEventArg->getOutputResultQueue()->pop();
}

if( NULL == task && NULL == msg ) {
event_base_loop( mEventArg->getEventBase(), EVLOOP_ONCE );
}
}

/* leader end */

pthread_mutex_unlock( &mMutex );


/* worker begin */

if( NULL != task ) task->run();

if( NULL != msg ) mCompletionHandler->completionMessage( msg );

/* worker end */
}


在 run 函数中,启动线程池中的多个线程运行 lfHandler ,
由 lfHandler 不断地运行 handleOneEvent 。
线程的角色转变在上面的注释中可以很清楚地看到。

由于这里的实现比较简单,LF 线程池的线程都是预先创建的,
并且没有实现线程池之外的线程可以加入的功能,
所以在 leader 切换为 worker,并且提升一个 follower 为 leader 的时候,
只需要用一个 mutex 就可以解决了。


 ruchong 回复于:2007-07-06 14:32:25

下了编译不过.
localhost spserver-0.6 # make
gcc -Wall -D_REENTRANT -D_GNU_SOURCE -g -fPIC -I../libevent/ -c event_msgqueue.c -o event_msgqueue.o
event_msgqueue.c:18:20: error: config.h: No such file or directory
In file included from event_msgqueue.c:19:
event_msgqueue.h:15:19: error: event.h: No such file or directory
In file included from event_msgqueue.c:19:
event_msgqueue.h:24: warning: ‘struct event_base’ declared inside parameter list
event_msgqueue.h:24: warning: its scope is only this definition or declaration, which is probably not what you want
event_msgqueue.c:37: error: field ‘queue_ev’ has incomplete type
event_msgqueue.c:161: warning: ‘struct event_base’ declared inside parameter list
event_msgqueue.c:161: error: conflicting types for ‘msgqueue_new’
event_msgqueue.h:24: error: previous declaration of ‘msgqueue_new’ was here
event_msgqueue.c: In function ‘msgqueue_new’:
event_msgqueue.c:187: warning: implicit declaration of function ‘event_set’
event_msgqueue.c:187: error: ‘EV_READ’ undeclared (first use in this function)
event_msgqueue.c:187: error: (Each undeclared identifier is reported only once
event_msgqueue.c:187: error: for each function it appears in.)
event_msgqueue.c:187: error: ‘EV_PERSIST’ undeclared (first use in this function)
event_msgqueue.c:188: warning: implicit declaration of function ‘event_base_set’
event_msgqueue.c:189: warning: implicit declaration of function ‘event_add’
event_msgqueue.c: In function ‘msgqueue_destroy’:
event_msgqueue.c:202: warning: implicit declaration of function ‘event_del’
make: *** [event_msgqueue.o] Error 1


 清汤挂面 回复于:2007-07-06 15:26:29

引用:原帖由 iunknown 于 2007-7-5 13:20 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7009867&ptid=957813]


多谢!你这样说,我很大压力啊。。。。。:) 

关于 HSHA , LF 线程池,还有 reactor ,proactor 这些模式,目前能找到的参考实现有 ACE 和 twisted 。
不知这里有没有人做过类似的框架?或者有没有人希 ... 



I've done the reactor service frame


 iunknown 回复于:2007-07-06 19:26:06

引用:原帖由 ruchong 于 2007-7-6 14:32 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7016219&ptid=957813]
下了编译不过.
localhost spserver-0.6 # make
gcc -Wall -D_REENTRANT -D_GNU_SOURCE -g -fPIC -I../libevent/ -c event_msgqueue.c -o event_msgqueue.o
event_msgqueue.c:18:20: error: config.h: No suc ... 



请阅读 [url=http://spserver.googlecode.com/svn/trunk/README]README 文件,请先检查是否安装了 libevent,确认安装之后,修改 Makefile 指定 libevent 的路径。

引用:
2.Building

Before building spserver, libevent must been installed. Test with libevent 1.1 and 1.2.

You can donwload libevent from its home page:

http://www.monkey.org/~provos/libevent/

Edit spserver/Makefile to specify the path of libevent:

LIBEVENT_INCL = -I<path_to_libevent_include>
LIBEVENT_LIB  = -L<path_to_libevent_library> -levent




[ 本帖最后由 iunknown 于 2007-7-6 19:53 编辑 ]


 iunknown 回复于:2007-07-06 19:41:57

引用:原帖由 清汤挂面 于 2007-7-6 15:26 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7016559&ptid=957813]


I've done the reactor service frame 



reactor 是按 ACE 的接口来实现,还是按 libevent 的接口来实现?
ACE 使用的是 OO 的接口,libevent 使用的是 C 的 callback 。

ACE 基于 OO 的接口

class Event_Handler {
pupblic:
    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;
};


libevent 基于 C 的 callback 的接口

void event_set(struct event * ev, int fd, short event, 
void ( * fn)(int, short, void * ), void * arg);


fn 就是 calback,通常的实现类似

void fifo_read(int fd, short event, void *arg);


libevent 的实现方式,其实类似于 《unix网络编程》 (第二版,中文版) Page 141 和 Page 148 的代码。可以看看这里的说明:http://iunknown.javaeye.com/blog/41077

一般情况下,如果业务处理逻辑不涉及过多的 IO 操作,使用单线程运行reactor 的效果是非常好的。比如 memcached 在 1.2 之前的版本就是单线程运行 libevent 实现的,性能非常好。在 memcached 中只有网络请求和响应是 IO 操作,内部的处理逻辑只是 HASH 表的查找和维护,不会造成阻塞,因此使用单线程是完全没有问题的。

但如果业务处理逻辑还涉及很多其他的 IO 操作的话,那么或者把这些 IO 操作也纳入 reactor 的控制,要么就需要使用多线程了。但在某些情况下,业务中涉及的 IO 操作是类似数据库查询这样的 IO 操作,这些 IO 操作很难纳入 reactor 的控制,就要使用多线程了。

[ 本帖最后由 iunknown 于 2007-7-6 19:49 编辑 ]


 NewCore 回复于:2007-07-06 22:09:25

学习一下设计思路.


 iunknown 回复于:2007-07-07 09:10:11

在 SPServer 中自带了几个使用 SPServer 框架实现的 demo :testecho.cpp ,testsmtp.cpp , testchat.cpp ,testhttp.cpp 。

testecho.cpp 是 echo 服务器。http://spserver.googlecode.com/svn/trunk/testecho.cpp
testchat.cpp 是 chatroom 服务器。http://spserver.googlecode.com/svn/trunk/testchat.cpp
testsmtp.cpp 是 fake smtp 服务器。http://spserver.googlecode.com/svn/trunk/testsmtp.cpp
testhttp.cpp 是 echo http 服务器,把接收到的 http 请求解释出来,把请求的信息输出为一个 html 返回。
http://spserver.googlecode.com/svn/trunk/testhttp.cpp

echo 服务器和 chatroom 服务器应该是很多学网络编程的人完成的第一个完整的应用程序。
使用 SPServer 框架实现的这两个服务器,主要的特点就是开发者(指框架的使用者,不是框架的实现者)只需要处理内存对象,而不需要处理网络 IO ,所有的网络 IO 都由 SPServer 框架来处理。在 echo 这种相对比较简单的服务器上,对开发者屏蔽网络 IO 带来的好处可能不见的很大,但是对于 chatroom 这类相对复杂的服务器,对开发者屏网络 IO 就可以带来很大的好处,开发者可以专住于实现 chatroom 的业务逻辑,开发者所面对的都是内存对象。

testsmtp.cpp 主要是用来演示对于 smtp 这样的协议,SPServer 是怎么支持的。testsmtp 实现的是一个空的 smtp 服务器,能够完成标准的 smtp 应答,不过实际上内部什么事都没干,:) 

以上这些 demo 都可以使用自带的 teststress 测试 工具来做压力测试。

bash-2.05a$ ./testecho 

bash-2.05a$ ./teststress -p 3333 -c 100 -m 100
Create 100 connections to server, it will take some minutes to complete.
..........

Test result :
Clients : 100, Messages Per Client : 100
ExecTimes: 5.308419 seconds

client  Send    Recv
total : 10000   10100



testhttp.cpp 是一个 echo http 服务器。可以使用 apache 自带的 ab 工具对 testhttp.cpp 进行测试。
引用:
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)  



[ 本帖最后由 iunknown 于 2007-7-7 09:23 编辑 ]


 queue 回复于:2007-07-10 13:04:04

引用:原帖由 iunknown 于 2007-7-6 19:41 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7017812&ptid=957813]

ACE 基于 OO 的接口

class Event_Handler {
pupblic:
    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;
};





看了一下代码,SPServer 实现的不是类似 Event_Handler 这样的接口,而是

class SP_Handler {
public:
virtual ~SP_Handler();

// 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;
};


这个接口更类似 proactor ,而不是 reactor 。接口上体现的不是 event ,而是 result 。


 iunknown 回复于:2007-07-10 19:39:21

引用:原帖由 queue 于 2007-7-10 13:04 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7030950&ptid=957813]


这个接口更类似 proactor ,而不是 reactor 。接口上体现的不是 event ,而是 result 。 



不错,SPServer 其实更像 proactor 。之前在这里也讨论得到类似的结果

http://iunknown.javaeye.com/blog/post/320133

引用:
呵呵,这两天重新看 POSA2 关于 reactor/proactor 的论述,理解的更多了一点。对于 spserver ,我也有这种看法。

reactor 和 proactor 的主要区别:
proactor 是由于异步操作的完成事件触发 handler 的执行,reactor 是由于产生了可以进行非阻塞操作的事件触发 handler 的执行。

libevent 可以说是一个 reactor 的实现。这一点通过对比 reactor 的 Event_Handler 和 libevent 的 callback ,可以和清楚地看到是非常类似的。两者在接口上,体现的是 IO 句柄是否可读或可写。

spserver 也就是相当于基于 libevent 的 reactor 封装了一个 proactor 出来。也是从对比 proactor 和的 Complete_Handler 和 SP_Handler 可以看出来。两者在接口上,体现的是异步操作的结果:proactor 是 Async_Result ,spserver 是 SP_Request->getMsgDecoder() 。




找到了一个用模拟 async IO 来实现 Proactor 的文章。
[url=http://www.artima.com/articles/io_design_patterns2.html]Comparing Two High-Performance I/O Design Patterns
ACE  自带的 proactor 只能在支持异步 IO 的操作系统上才能使用,比如 windows 有 overlapped ,部分 unix 平台有  aio 。
这篇文章描述了如果使用 event-driven 来模拟异步 IO ,从而实现 proactor 模式。

在开发 SPServer 之前也曾看到过这篇文章,不过当时没留意,也没完全理解它的意思。后来经过讨论才发现 SPServer 的做法和它描述的做法非常相似。


 queue 回复于:2007-07-11 13:19:06

引用:
找到了一个用模拟 async IO 来实现 Proactor 的文章。
Comparing Two High-Performance I/O Design Patterns
ACE  自带的 proactor 只能在支持异步 IO 的操作系统上才能使用,比如 windows 有 overlapped ,部分 unix 平台有  aio 。
这篇文章描述了如果使用 event-driven 来模拟异步 IO ,从而实现 proactor 模式。



Comparing Two High-Performance I/O Design Patterns 这篇文章不错,有没有考虑过按照这篇文章所说的设计基于 libevent 来实现一个正宗的 proactor ?这篇文章提到的 TProactor 仍然依赖于 ACE ,如果基于 libevent 实现一个 proactor,应该算是一个轻量级的 proactor,应该还不错。

PS:不知道有没有人知道有另外的轻量级的 proactor 的实现?


 iunknown 回复于:2007-07-11 20:56:09

引用:有没有考虑过按照这篇文章所说的设计基于 libevent 来实现一个正宗的 proactor ?这篇文章提到的 TProactor 仍然依赖于 ACE ,如果基于 libevent 实现一个 proactor,应该算是一个轻量级的 proactor,应该还不错。


对于“正宗”的 ACE Proactor 接口怎么和线程池结合还没有搞得很清楚。ACE 自带的例子看得不是很明白。
找时间重新看看 ACE 的例子,期望能够看得明白些,到时再考虑是否实现一个“正宗”的 Proactor 。
就目前实现的这个“非正宗”的 Proactor ,主要的差距是使用者对于 Proactor 的操作受到比较多的限制,没有“正宗”的 Proactor 那么灵活。在 0.5 版本中加入了一个 Dispatcher 的类,部分地解决了这个问题,使得核心的线程池框架可以应用到 server socket ,也可以应用到 client socket 上。

[ 本帖最后由 iunknown 于 2007-7-11 20:59 编辑 ]


 queue 回复于:2007-07-13 13:11:29

引用:在 0.5 版本中加入了一个 Dispatcher 的类,部分地解决了这个问题,使得核心的线程池框架可以应用到 server socket ,也可以应用到 client socket 上。


看了一下 dispatcher 的例子,可以考虑在搞一个进程池 framework 出来,加上这个 dispatcher 就可以实现 apache 的 worker 模型了。按 apache 的做法,设定每个进程最多服务器的请求数,然后自动退出,依靠进程退出时自动回收资源,这样可以使得整个 framework 的稳定性非常好。

在这个论坛好像看到有不少人实现了进程池,不知道有没有人结合进程池和线程池做过实际的应用?


 iunknown 回复于:2007-07-18 21:56:40

引用:原帖由 queue 于 2007-7-13 13:11 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7048233&ptid=957813]


看了一下 dispatcher 的例子,可以考虑在搞一个进程池 framework 出来,加上这个 dispatcher 就可以实现 apache 的 worker 模型了。按 apache 的做法,设定每个进程最多服务器的请求数,然后自动退出,依靠 ... 



有这样的想法,最近也做了一些 research,看了一些现有的 进程池 framework,包括 apache,fastcgi,tinycxx等,正在熟悉进程池 framework 的设计。
fastcgi 的一个实现 --  mod_fcgid ,里面的进程池实现得不错,可惜就是和 apache 结合的太紧密了,要单独抽离出来比较困难。


 iunknown 回复于:2007-08-11 13:24:02

spserver 0.7 版本发布。这个版本最大的亮点是开始支持 ssl 。
1。spserver 中 socket 相关的操作被抽象为 IOChannel 层
2。ssl 的相关代码被实现为一个 plugin (libspopenssl.so),对于不需要使用 ssl 的用户,不需要引入 ssl 相关的头文件和库
3。原有的使用 spserver 实现的程序,不受影响。如果想使用 ssl 功能,那么只需要增加少数几行代码即可。

代码可以到主页下载:http://code.google.com/p/spserver/

一个 echo 程序的例子
http://spserver.googlecode.com/svn/trunk/openssl/testechos.cpp

        SP_Server server( "", port, new SP_EchoHandlerFactory() );

        SP_OpensslChannelFactory * opensslFactory = new SP_OpensslChannelFactory();
        opensslFactory->init( "demo.crt", "demo.key" );
        server.setIOChannelFactory( opensslFactory );

        server.runForever();


[ 本帖最后由 iunknown 于 2007-8-11 13:26 编辑 ]


 zsniper 回复于:2007-08-15 17:32:21

认真拜读LZ的blog。。。。。。


 zsniper 回复于:2007-08-16 15:39:43

LZ能用C写一个这样的库吗?
我尝试着把它专成C的,呵呵。。。技术不够,还有好多没读懂哦。。。


 iunknown 回复于:2007-08-16 20:04:49

引用:原帖由 zsniper 于 2007-8-16 15:39 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7217941&ptid=957813]
LZ能用C写一个这样的库吗?



其中的线程池部分开始是用纯 C 实现的。
http://iunknown.javaeye.com/blog/38544

如果要把 SPServer 移植到 C 上面,应该不是太难。
SPServer 很少用继承,大部分是采用基于对象范式(object-based paradigm)来实现的。
用基于对象的方式设计的类,可以很容易地用 struct + global function 来实现。
唯一的用了继承的地方是 SP_Handler ,但是这个 SP_Handler 全部是纯虚函数,也可以用一个包含多个函数指针的 struct 来替代。

不过我暂时没有计划移植到 C 上,暂时想进一步完善现有的代码。


 iunknown 回复于:2007-08-22 22:33:07

在实现了 ssl 的支持之后,使用 spserver 来实现一个 ssl proxy ,就很简单了。
为 spserver 增加了一个名为 sptunnel 的可执行程序,这是一个通用的 TCP ssl proxy 程序。
通用的意思就是可以作为任何给予 TCP 协议服务器做 ssl proxy,比如 http、smtp、pop3 这类。
在最新的 0.8 release 中,重构了一下目录,分开了 spserver 最基本的功能和各个插件。

最新代码下载:http://spserver.googlecode.com/files/spserver-0.8.src.tar.gz

sptunnel 的用法如下所示,默认侦听在 8080 端口,并转发到 google.com 。
运行之后,可以使用 IE 或者 firefox 来访问:https://<ip.of.sptunnel>:8080/


bash-2.05a$ ./sptunnel -v
Usage: ./sptunnel [-p <port>] [-t <threads>] [-r <backend>]

bash-2.05a$ ./sptunnel -r 66.249.89.99:80
sptunnel[7437]: Backend server - 66.249.89.99:80
sptunnel[7437]: Listen on port [8080]


[ 本帖最后由 iunknown 于 2007-8-22 22:37 编辑 ]


 zsniper 回复于:2007-10-24 09:36:07

请问楼主,假如client主动关闭连接,spserver如何得知

还有为什么close(fd)关不掉socket


 zsniper 回复于:2007-10-28 19:39:00

请问楼主,是不是因为没有event_del(fd),close(fd)才不会激发FIN????


 fengdays 回复于:2007-11-16 17:58:32

牛人,问个低级问题

编译出错,错误如下

event_msgqueue.c:125: error: previous definition of 'circqueue_pop_head' was here
event_msgqueue.c:138: error: redefinition of 'msgqueue_pop'
event_msgqueue.c:138: error: previous definition of 'msgqueue_pop' was here
event_msgqueue.c:138: error: redefinition of 'msgqueue_pop'
event_msgqueue.c:138: error: previous definition of 'msgqueue_pop' was here
event_msgqueue.c:161: warning: "struct event_base" declared inside parameter list
event_msgqueue.c:161: error: redefinition of 'msgqueue_new'
event_msgqueue.c:161: error: previous definition of 'msgqueue_new' was here
event_msgqueue.c:161: error: redefinition of 'msgqueue_new'
event_msgqueue.c:161: error: previous definition of 'msgqueue_new' was here
event_msgqueue.c: In function `msgqueue_new':
event_msgqueue.c:187: error: `EV_READ' undeclared (first use in this function)
event_msgqueue.c:187: error: `EV_PERSIST' undeclared (first use in this function)
event_msgqueue.c: At top level:
event_msgqueue.c:197: error: redefinition of 'msgqueue_destroy'
event_msgqueue.c:197: error: previous definition of 'msgqueue_destroy' was here
event_msgqueue.c:197: error: redefinition of 'msgqueue_destroy'
event_msgqueue.c:197: error: previous definition of 'msgqueue_destroy' was here
event_msgqueue.c:209: error: redefinition of 'msgqueue_push'
event_msgqueue.c:209: error: previous definition of 'msgqueue_push' was here
event_msgqueue.c:209: error: redefinition of 'msgqueue_push'
event_msgqueue.c:209: error: previous definition of 'msgqueue_push' was here
event_msgqueue.c:223: error: redefinition of 'msgqueue_length'
event_msgqueue.c:223: error: previous definition of 'msgqueue_length' was here
event_msgqueue.c:223: error: redefinition of 'msgqueue_length'
event_msgqueue.c:223: error: previous definition of 'msgqueue_length' was here
make: *** [event_msgqueue.o] 错误 1


这种错误应该是头文件包含上出错了吧,应该是头文件被包含多次吧?
我这用的是RedHat fc6
或者是否.c文件 gcc编译的问题呢?请指教一下!多谢!!:em03:


 iunknown 回复于:2007-11-17 21:23:01

引用:原帖由 zsniper 于 2007-10-24 09:36 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7503463&ptid=957813]
请问楼主,假如client主动关闭连接,spserver如何得知

还有为什么close(fd)关不掉socket 




抱歉,很久没有来 CU 看看。

如果 client 主动关闭连接,那么先调用 SP_Handler::error ,然后调用 SP_Handler::close 。
spserver 认为 client 主动关闭连接是一种错误。通常设计良好的协议都会有一个 client 和 server 的协商关闭的指令。
在 spserver 中,通过 SP_Handler::handle 返回 -1 来指示 server 主动关闭连接。

close(fd) 关不掉 socket ?能说明一下上下文吧?是指在 spserver 中吗?

[ 本帖最后由 iunknown 于 2007-11-17 21:24 编辑 ]


 iunknown 回复于:2007-11-17 21:29:45

引用:原帖由 fengdays 于 2007-11-16 17:58 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7601136&ptid=957813]

编译出错,错误如下

event_msgqueue.c:125: error: previous definition of 'circqueue_pop_head' was here
event_msgqueue.c:138: error: redefinition of 'msgqueue_pop'
event_ms ... 



刚刚找了一台 RedHat FC 试了一下,没有问题,可以编译。请提供一下 gcc 的版本。

-bash-3.1$ gcc --version
gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

-bash-3.1$ cat /etc/redhat-release 
Fedora Core release 6 (Zod)

-bash-3.1$ uname -a
Linux xxxxx 2.6.22.7-57.fc6 #1 SMP Fri Sep 21 19:45:12 EDT 2007 x86_64 x86_64 x86_64 GNU/Linux

[ 本帖最后由 iunknown 于 2007-11-17 21:53 编辑 ]


 fengdays 回复于:2007-11-19 09:20:31

gcc --version 
gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-8)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


 fengdays 回复于:2007-11-19 09:32:52

gcc --version 
gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-8 )
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


uname -a
Linux Car-2 2.6.9-55.0.2.ELsmp #1 SMP Tue Jun 26 14:30:58 EDT 2007 i686 i686 i386 GNU/Linux

cat /etc/redhat-release
CentOS release 4.5 (Final)


晕啊,是CentOS啊, 唉! 原来不是FC!  服务器是维护部门安装的,我要求他们安装FC的啊,真晕! 

这样的话是不是要更新一下gcc编译器版本啦?


 zsniper 回复于:2007-12-18 09:32:03

请问LZ,你的SP框架的服务器,是那种客户机请求,服务器相应的模式,那假如服务器主动广播,该如何使用你的这个框架呢~?

是不是再本地建立一个连接,好像GM一样 , 向在线的所有人广播?


还是直接创建一个广播task,压入input_queue中?

[ 本帖最后由 zsniper 于 2007-12-18 09:50 编辑 ]


 zsniper 回复于:2007-12-18 09:42:33

引用:原帖由 iunknown 于 2007-11-17 21:23 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7603477&ptid=957813]



抱歉,很久没有来 CU 看看。

如果 client 主动关闭连接,那么先调用 SP_Handler::error ,然后调用 SP_Handler::close 。
spserver 认为 client 主动关闭连接是一种错误。通常设计良好的协议都会有一 ... 




谢谢lz,是我犯了个低级错误,在testecho中定义了一个close()函数,结果程序在close(socket)的时候,调用的是我自己定义的这个close()

呵呵。。。


 iceviewer 回复于:2007-12-18 09:54:58

:mrgreen:  学习中,谢谢啦


 iunknown 回复于:2007-12-18 13:09:19

引用:原帖由 zsniper 于 2007-12-18 09:32 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7732992&ptid=957813]
请问LZ,你的SP框架的服务器,是那种客户机请求,服务器相应的模式,那假如服务器主动广播,该如何使用你的这个框架呢~?

是不是再本地建立一个连接,好像GM一样 , 向在线的所有人广播?


还是直接创建 ... 



SPServer 目前已经实现的广播功能是针对聊天室这种功能,在同一个聊天室中的各个 client 之间广播消息。
如果要实现服务器主动广播,目前来说只能使用你提到的“在本地建立一个连接,好像GM一样 , 向在线的所有人广播”。
采用这种方法,这个本地连接发送一个特殊的数据包过去,在 SP_Handler::handle 中识别出这个特殊数据包,从而触发广播事件。


 zsniper 回复于:2007-12-18 13:24:40

恩。。。谢谢LZ,我想了一下也只有这种方式。。。


 zsniper 回复于:2007-12-28 10:31:09

再次请问LZ,HAHS和LF,感觉都是那种高并发的服务器 ,感觉他的相应不是很快?


 iunknown 回复于:2007-12-28 23:31:21

引用:原帖由 zsniper 于 2007-12-28 10:31 发表 [url=http://bbs.chinaunix.net/redirect.php?goto=findpost&pid=7779163&ptid=957813]
再次请问LZ,HAHS和LF,感觉都是那种高并发的服务器 ,感觉他的相应不是很快? 



之前曾经用 spserver 实现过一个类似 memcached 的 spcached ,测试结果如下
# 500000 sets: 229266ms     2173 次每秒 
# 500000 gets: 284856ms     1754 次每秒
采用的是长连接。
具体的测试数据可以参考:http://iunknown.javaeye.com/blog/80095

刚刚又测试了短连接的情况,采用了测试 spprocpool 的方法。

spprocpool的测试结果:http://bbs.chinaunix.net/thread-1026543-1-4.html
Leader/Follower       2635 / 100 = 26.35 (毫秒)
Descriptor Passing   3644 / 100 = 36.44 (毫秒)

spserver的测试结果:
Leader/Follower 10 个线程:5220 / 100 = 52.2 (毫秒)
HAHS 10 个线程:  10126 / 100  = 101.26 (毫秒)

测试结果比进程池差,因为在进行这个测试的过程中,使用 spserver 实现的时候,多了一些队列管理和内存的 copy 。
这些多出来的队列管理和内存 copy 主要的目前就是为了提高并发度。

如果不使用 spserver ,直接使用一个连接一个线程的线程池方式,估计和进程池应该差不多。
但是这种 Thread Per Connection 的方式,在并发度上就不如 spserver 了。

[ 本帖最后由 iunknown 于 2007-12-28 23:34 编辑 ]




原文链接:http://bbs.chinaunix.net/viewthread.php?tid=957813
转载请注明作者名及原文出处


文章评论

共有 位网友发表了评论 查看完整内容