这段代码可以看作是程序的主循环,它不断的从socket读取代码,然后调用mock对象,触发其中定义的行为。一个mock对象定义了一个行为,程序充许一次定义的多个mock,也有使得程序可以模拟比较复杂的行为了。
下面再看看mock对象里面是如何定义的
if reduce( lambda x,y:x and y, map(lambda f:f(handler),self.on_list), True ): print 'Invoke Mock:',self.on_list,self.do_list map(lambda f:f(handler),self.do_list) return True return False |
这里用到了一点儿函数式编程的技巧,在on_list中保存了当前mock的触发条件,do_list中则保存了当前mock要执行的操作,这段代码的就意思就是当所有的触发条件都满足时,就顺序执行操作列表的中的操作,否则就退出。
上面两段代码就构成了Mock Server的核心逻辑。
条件与结果
接下来我们看看on_list和do_list里面到底是什么,以前面的CASE中用到的large_than和send_back为例,它们的原始定义如下所示:
@mock_action return len(handler.buffer)>=size @mock_action return handler.sock.sendall(data) |
可以看到,它们的第一参数都是handler,它代表了当前请求处理器的实例,包含以下几个基本的成员:
● client_address 当前请求的客户端地址
● sock 当前请求的socket对象
● buffer 当前请求的数据缓冲区
● stop 主程序停止标志
对照 核心代码 中的主循环,这里的handler就是循环中的self,这样就不难明白这几个成员的作用了。
在on_list和do_list中保存就是对这些函数的“间接”引用。那什么是间接引用呢?
回头看前面CAE中的代码:
Mock.on( large_than(192), #当接收的数据长度大于192字节时(一个正常请求的最小长度) ).do( send_back( #返回下面的数据包 am_head_t( …… …… ) ) |
看以看到这里并没有给large_than和send_back传入handler参数,而且,熟悉Python语法的人也会发现,这是对函数的调用,而不是对函数对象本身的引用,最终on方法得到的参数应该是large_than执行完的结果,不是large_than这个函数对象。说了这么多,好像很混乱的样子,其实密秘就在
@mock_action中,这个是python中的函数修饰器,它本身也是一个函数,接受一个函数对象为参数,返回一个新的函数对象,来看看mock_action的定义:
def mock_action(f): def factor(*args): action=lambda h:f(h,*args) factor.is_mock_action=True #暂时无用 |