一、问题的提出
因为web和原有系统互通的需要,而原系统已经有基于tcp的长连接API。由于web客户端是并发性的访问,而老系统的API是C2C的对等长连接通信,不允许多个客户端同时连接一个服务器。因此要在原有C系统与web间搭建起互通的适配层,将web的通信协议与内部系统间对接起。
二、解决方案
早先曾考虑用JNI的方式把api包装下,但JNI在处理字符串的时候,经常会有字符集转换的问题。再则,JNI搞定了java,那php、RoR等又得一个个的单独实现,比较费时,因此改用语言无关的方案。
基于这个需求,想来python最合适干这个,原因有三:
1、python标准库里的协议集最全面,随手可得不说,还有标准的doc和一些立即可以run的example,这对于为web提供服务来说,最容易不过;
2、python对c的集成也是非常容易的
3、python代码的简洁性是有目共睹的,包括简洁的语法、大量唾手可得的标志模块,如日志系统、线程等等
选定python,就着手开始下一步,选定与web的协议。考虑到web client不能也定死到python,应该允许使用php、java等任意web语言使用本模块的可能性。因此可选的方案必须要符合语言无关的特点(当然也是平台无关的),可选的方案有:webservice、xmlrpc、REST等。因为ws过于复杂而REST还需要自己定义参数格式,最后选择了xmlrpc这种既简洁又具有参数类型的协议(xmlrpc在参数的前面添加类别定义信息,一般的xmlrpc协议栈都会根据该定义将数据转换到与语言对应的类型上来)
至于原有CAPI的包装,已有非常多的文章,可以google下,笔者常用的是Boost.Python,非常简单,差不多是公式性代码,这里不再藉述。
三、具体实现
接下来就开始实现这个xmlrpcserver,python里就有一个SimpleXMLRPCServer的,在python的帮助里还有示例代码:
服务器侧:
from SimpleXMLRPCServer import SimpleXMLRPCServer
# Create server
server = SimpleXMLRPCServer(("localhost", 8000))
server.register_introspection_functions()
# Register pow() function; this will use the value of
# pow.__name__ as the name, which is just 'pow'.
server.register_function(pow)
# Register a function under a different name
def adder_function(x,y):
return x + y
server.register_function(adder_function, 'add')
# Register an instance; all the methods of the instance are
# published as XML-RPC methods (in this case, just 'div').
class MyFuncs:
def div(self, x, y):
return x // y
server.register_instance(MyFuncs())
# Run the server's main loop
server.serve_forever()
客户端侧:import xmlrpclib
s = xmlrpclib.Server('http://localhost:8000')
print s.pow(2,3) # Returns 2**3 = 8
print s.add(2,3) # Returns 5
print s.div(5,2) # Returns 5//2 = 2
# Print list of available methods
print s.system.listMethods()
windows下开两个pyshell,先运行服务器侧的代码,然后输入客户端的代码,马上就能看到结果。
一切进展顺利,然后新问题出现了。
三、性能优化与改进
这个适配层很通用,意味着可能被用来做为多个web与多个后台系统间的统一中间层,而这个SimpleServer里没有看到任何并发的概念,因此立即修改了server的一个函数,增加了time.sleep。果然,如我所料,全部调用都是串行的。这在web与后台系统的集成中是会经常发生的。
因此需要解决两个问题:
1、如何把两个请求独立开来处理,不能因为某个调用阻塞了其他所有的请求
2、web有超时的概念,这个xmlrpc该如何处理
先来看第一个问题,google了资料。有人说要改python库的代码,有人说用twisted。
虽然鄙人早先使用VC的时候,曾有过修改MFC代码的时候,但深知这种修改所带来的麻烦。在VC的工程里如果修改了MFC代码,几个人合作的项目要让别人也编译过是多么的麻烦不说,就算是自己过段时间重装了windows后再来修改几个月前的项目,也会遇到不少麻烦,因此不可取。twisted到其网站上查找xmlrpc,得到的答案是这个东西对xmlrpc的支持很勉强。因此还决定采用C++里的常用模式,copy出pyhton里的SimpleXMLRPCServer来,自己修改后重新命名成自己的。其实因为python强大的标准库,修改起来很简单。只需要:
from SimpleXMLRPCServer import SimpleXMLRPCDispatcher, SimpleXMLRPCRequestHandler
from SocketServer import ThreadingTCPServer
try:
import fcntl
except ImportError:
fcntl = None
class MyXMLRPCServer(ThreadingTCPServer,
SimpleXMLRPCDispatcher):
"""Simple XML-RPC server.
Simple XML-RPC server that allows functions and a single instance
to be installed to handle requests. The default implementation
attempts to dispatch XML-RPC calls to the functions or instance
installed in the server. Override the _dispatch method inhereted
from SimpleXMLRPCDispatcher to change this behavior.
"""
allow_reuse_address = True
def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
logRequests=True, allow_none=False, encoding=None):
self.logRequests = logRequests
SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
ThreadingTCPServer.__init__(self, addr, requestHandler)
# [Bug #1222790] If possible, set close-on-exec flag; if a
# method spawns a subprocess, the subprocess shouldn't have
# the listening socket open.
if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
然后把原有代码里的SimpleXMLRPCServer换成MyXMLRPCServer就行了。查看ThreadingTCPServer的代码,可以看到其核心实际上是基类的ThreadingMixIn里的process_request方法,在每个request到来时,都是很简单的启动一个python里的threading:
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
import threading
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
if self.daemon_threads:
t.setDaemon (1)
t.start()
再明显不过,因此多线程问题得到解决。如果实际系统在运行的时候,发现这种“不受控”的开启线程过于“并发”,当然可以自己实现一个ThreadingMixIn,仿照Python库里的方式足组合一把。
遗留问题:
1、API调用的超时问题该如何解决
2、 Java客户端代码
分享到:
相关推荐
这是软件大型实验周的课设作品,用来实现一个简单的 CA 系统,它包含以下功能: 证书生成:用户提供 Certificate Signing Request (CSR)和 公钥后,系统会自动为用户生成证书并通过邮箱发放,支持 用于 SSL 和代码...
标题“使用Python实现基于Web的水资源监测系统”表明本文将重点讨论如何利用Python编程语言来建立一个基于Web的水资源监测系统。在正文开始部分,作者简要介绍了Python的特性,并阐述了基于Web的水资源监测系统的...
GB28181使用python实现源码 作为上级域对接海康蓝盾平台。包括catalog设备信息,预览设备视频流保存成本地文件以及球机PTZ控制 参考博文 ps流 h264解析 ...
基于Python的Flask实现WEB后台权限管理系统源码+使用文档.zip基于Python的Flask实现WEB后台权限管理系统源码+使用文档.zip基于Python的Flask实现WEB后台权限管理系统源码+使用文档.zip基于Python的Flask实现WEB后台...
python web开发,基于flask的练手项目---文件上传下载的管理系统的设计与实现python web开发,基于flask的练手项目---文件上传下载的管理系统的设计与实现python web开发,基于flask的练手项目---文件上传下载的管理...
综上所述,这个Python实现的选课管理系统课程设计涵盖了从基础的编程概念到高级的Web开发技术,涉及到数据库操作、用户认证、Web框架、API设计等多个方面,是学习和实践Python Web开发的一个全面案例。
基于python3编写的web后台管理系统,基于layui采用Django框架实现完整的后台管理系统,包含菜单权限、机构权限、数据权限等,功能齐全。 基于python3编写的web后台管理系统,基于layui采用Django框架实现完整的...
Python基于Django框架实现的一个学生信息管理系统源码 Python基于Django框架实现的一个学生信息管理系统源码 Python基于Django框架实现的一个学生信息管理系统源码 Python基于...
"基于Python实现的实验信息综合管理系统.7z" 这个标题指出,我们有一个使用Python编程语言开发的系统,该系统专注于实验信息的管理和综合处理。.7z是压缩文件格式,意味着所有相关的源代码、文档和其他资源都被打包...
Python因其简洁的语法和丰富的库支持,在数据分析、Web开发和系统管理等领域广泛应用,同样适用于构建实验室信息管理系统。 该系统的核心功能是提供实验信息的查询服务,这表明它具备数据存储、检索和展示的能力。...
8. 集成与扩展:Python拥有丰富的生态系统,能够轻松与其他系统集成,如通过Flask或Django开发Web接口,或者通过RESTful API与其他服务交互。 9. 安全性:为了保护态势感知系统本身的安全,需要采用安全编码实践,...
由于Java的RSA加解密一般都是用RSA/ECB/PKCS1PADDING,导致Python一般的RSA加密库的加解密结果与Java的不兼容,Python下目前能与之兼容的RSA的库目前发现的只有一个,就是m2crypto。 这个库目前的问题是在windows...
用Python实现一个软件自动升级系统。设计思路很简单:当有新版本需要发布时,将文件放在服务端,生成一个记录每个文件变化的配置文件。客户端本地也有一个记录文件信息的配置文件,客户端检查更新时,将服务端的配置...
由于大华SDK可能是用C/C++等语言编写的,因此通过ctypes库可以很方便地实现Python代码与C语言代码之间的交互。 另外,文档中还提到了SDK提供的回调函数,例如fDisConnect、fHaveReConnect等,它们用于处理连接断开...
Python以其简洁的语法和丰富的库而闻名,是数据分析、机器学习和Web开发等领域的首选语言。 在描述中提到的“java2python”工具,可能是一个开源项目或服务,用于自动化这个转换过程。这样的工具通常会解析Java源...
Java 在企业级应用、Web 开发和分布式系统中有着广泛的应用,而 Python 则在数据处理、科学计算和机器学习领域表现出色。为了结合两者的优势,我们经常需要在 Java 程序中调用 Python 脚本或库,以便利用 Python 的...