应用Python快速实现系统原型

来源:互联网 发布:8月份上海房产成交数据 编辑:程序博客网 时间:2024/04/30 22:21

应用Python快速实现系统原型

 

[摘要] 快速原型是在开发真实系统之前,构造一个原型,在该原型的基础上,逐渐完成整个系统的开发工作。Python非常易于使用,并且支持Windows/Mac/Unix/Linux/Solaris多操作系统平台,可以帮助开发人员在这些平台上更迅速地完成任务。同时Python拥有一个强大的基本类库和数量众多的第三方扩展库,所以它的应用范围也比较广泛。文章举例说明,如何应用Python快速实现一个异步多线程的前置机系统。

 

[关键词] 动态编程语言  快速原型开发 前置机 模拟系统

 

一、系统背景

在开发跨平台业务系统的时候,为了确保后台服务器的数据安全,客户端通常是与交易前置机通讯,发送交易请求,交易前置机接收交易请求,然后与后台服务器交互,从后台获得该交易的返回数据后,再按照交易报文的格式返回给客户端。

交易前置机所使用的操作系统情况较复杂,一般要根据客户单位的具体情况,有些采用Windows系统,有些采用Unix/Linux或者Solaris系统。但在去客户单位进行项目实施之前,开发人员需要在开发过程中随时进行客户端交易的调试工作,这就需要有个模拟交易前置机的系统,在调试过程中能非常方便的修改交易报文的定义,模拟后台返回的交易报文。在某些系统的开发中,这个模拟系统就可以作为一个完整系统的原型,开发系统的过程,就是在此原型基础上,逐渐完善交易类型与交易返回数据,最后完成整个系统的开发。

模拟系统的开发可以用多种方法来实现,而动态语言Python易于使用、类库丰富、修改方便。本文要阐述的是利用Python来进行模拟系统的开发,快速实现交易前置机最常用的功能:接收交易请求、组织返回数据、发送返回数据。

 

二、  Python的异(非阻塞)通讯

asyncore库是python的一个标准库,它是一个异步socket的包装。我们在进行网络通讯的时候可以直接使用socket等底层的库,但是asyncore使得我们可以更加方便的进行网络通讯,避免直接使用socket,select,poll等工具时需要面对的复杂处理。

asyncore库很简单,只包含了一个loop()函数和一个dispatcher基类。每一个从dispatcher继承的类的对象,都可以看作我们需要处理的一个socket,可以是TCP连接或者UDP。

asyncore库使用容易,我们只需要定义一个类,它继承dispatcher,然后我们重写(覆盖)一些方法就可以了。我们需要重写的方法一般都以handle_打头的。

loop()函数负责检测一个字典,字典中保存dispatcher的实例,这个字典被称为channel。每次创建一个dispatcher对象,都会把自己加入到一个默认的字典里面去。当对象被加入到channel中的时候,socket的行为都已经被定义好,程序只需要调用loop(),异步多线程通讯功能就准备好了。

 

三、  专注于业务处理

在我们的模拟系统中,由于需要同时为多个客户端服务,定义了一个主通讯服务类,继承自asyncore.dispatcher类,重写该类的handle_accept方法,从这里获得客户端的连接,向控制台输出客户端IP与端口信息,并转发给处理线程类。

处理线程类继承自asyncore.dispatcher_with_send,此类可以接收和发送数据,只需要重写handle_read方法即可。

这样,一个异步多线程的交易模拟系统就可以运行了。

每当客户端有数据发送过来,就会触发handle_read方法。在此方法中,可以对交易数据进行合法性判断、提取交易类别、提取交易数据、组织交易返回数据、发送数据到客户端,通过这一系列的处理,一个交易的完整过程就完成了。

在这里,通过对交易类别的判断,可以很容易的增加新的交易。

 

四、  代码摘要

1.导入库文件

import asyncore import socketimport sys

2.主通讯服务类

    类初始化时,创建socket连接,绑定在指定的端口上,并且可以设置最大的并发连接数,此处默认为10,最多可以同时为10个客户端服务。

    当客户端呼叫过来后,触发handle_accept方法,这里输出客户端IP地址和端口信息,启动处理线程类SecondaryServerSocket。

    客户端断开连接时,触发handle_colse方法,此方法也调用asyncore.dispatcher类的close方法,做一些善后处理工作。

class MainServerSocket(asyncore.dispatcher):def __init__(self, port):asyncore.dispatcher.__init__(self)self.create_socket(socket.AF_INET, socket.SOCK_STREAM)self.bind(('',port))#可以通过配置文件来设置最大连接数,目前是10个连接self.listen(10)      #最大可以同时为N个客户端服务def handle_accept(self):newSocket, address = self.accept( )print( "新的连接,来自{}".format(address) )SecondaryServerSocket(newSocket)def handle_close(self):asyncore.dispatcher.close(self)

 3.处理线程类

    此类继承自asyncore.dispatcher_with_send,当客户端发送交易报文过来时,触发handle_read方法。

    在handle_read方法中,根据具体的通讯协议,分析交易报文,然后针对不同的交易类型,分别进行处理。最后,处理好的交易报文,下发给对应的客户端。

 

class SecondaryServerSocket(asyncore.dispatcher_with_send):def handle_read(self):receivedHead = self.recv(4)if receivedHead:if (len(receivedHead)==4) and (receivedHead.isdigit() ):print( "报文头接收成功,报文长度:{}...".format(receivedHead) )receivedData = self.recv(int(receivedHead))print( "指定长度报文内容接收成功..." )#----------------------#0.特殊交易处理:服务器退出#----------------------if ( len(receivedData)==4 ) and ( receivedData.lower().endswith("exit") ) :self.close()print( "接收到退出命令,服务器退出!" )try:asyncore.close_all()returnexcept:sys.exit(0)return#----------------------#...正常交易的处理#----------------------。。。else:self.close()print( "接收到非法报文头!" )for x in range(len(receivedHead)):print hex(ord(receivedHead[x])) , " ",print()else: self.close( )def handle_close(self):print( "断开连接,来自{}.".format( self.getpeername( ) ) )

4.主程序入口

    程序从这里启动,首先打印程序帮助信息,然后在指定的侦听端口上,启动主通讯服务线程。

 

if __name__ == "__main__" :print __doc__MainServerSocket(3555)print( "服务器开始侦听..." )asyncore.loop( )


[参考资料]

1、《Python入门指南》Release2.5b2,作者:Guido van Rossum,2006.07.11,Python中国用户论坛集体翻译。

2、《Python核心编程》第二版,作者:(美)丘恩(Chun,W.J.),翻译:宋吉广,2008.07,北京:人民邮电出版社。

3、《深入Python :Dive Into Python中文版》5.4b,作者:MarkPilgrim, Python中国用户论坛集体翻译,Updated 审校 (5.4b):2007 年6 月—9 月