如何创建 pyserial Web 服务?
我编写了一个与 /dev/ttyS02 上的串行设备交互的 Web 应用程序。 问题是我当前的消息传递和排队解决方案。请阅读下文。
这是应用程序和pyserial之间的通信桥梁:
我的 Web 应用程序通过 PHP 将请求记录插入到 MySQL 中的 d_requests 表中。 插入记录的已处理列设置为 0。 插入的记录的 id 保存在 $id 变量中,并且 PHP 应用程序输入 循环状态,它将不断检查 d_requests[processed] 列是否 = 1 使用 $id 作为查找参考。
我有一个 python 守护进程服务,它每秒检查一次中的记录 d_requests 表,其中已处理列 = 0。 这被认为是一个新请求。(参考源代码 - python 服务)
然后,python 服务使用记录的信息通过以下方式连接到端口 pyserial。
执行请求的操作。然后记录的已处理列更新为 1 其他一些字段也更新了。 这将记录标记为已处理。
然后 PHP 控制块退出循环(第 1 点)并以 json 形式返回结果 结果
一些注意事项
- 串行设备每 250 毫秒能够处理 1 个请求。
- python 守护进程服务监视 d_requests 表以获取已处理的记录 每 1 秒列 = 0。
- 我的 Web 应用程序与 python 守护进程服务的唯一通信是 MySQL
DB 通过在 d_requests 表中插入请求记录。 - 我使用 PHP 块代码每秒使用插入的 id 来查找请求以进行检查 如果已处理列已更新为 1。
我的担忧
单点故障
当守护程序服务未运行时,无法发生串行请求
极端资源使用 strong>
我预计每秒向串行设备发出大约 4-5 个请求。使用当前的实现 为了处理消息,数据库将超时工作,CPU 使用率会很高,因为 PHP 应用程序和 python 守护进程/服务将连接数据库并在数据库上执行查询,并且请求处理会出现延迟。
结论: 有没有更好的方法来改进我当前的消息传递和排队解决方案? 我认为 pyserial Web 服务在这种情况下会很好用,例如串行端口。连接到网络套接字,例如。主机:<7000>我可以通过 PHP 向其发送请求并等待 Web 服务返回的响应。不幸的是我不知道该怎么做。
有什么想法吗?
谢谢
源代码
python 服务
import sys, time
from daemon import Daemon
import MySQLdb
#Database parameters
config = {"host":"localhost","username":"root","password":"cake","database":"mydb"}
#Check if MySQLdb library is present
try:
conn = MySQLdb.connect(config['host'],config['username'],config['password'],config['database'])
except MySQLdb.Error, e:
print "Error %d: %s" % (e.args[o], e.args[1])
sys.exit(1);
#Check if pyserial library is present
try:
import serial
except ImportError:
print "Error,pySerial module not installed"
sys.exit(1);
#Create DB cursor
#cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
#Declare global variables here
class MyDaemon(Daemon):
def run(self):
while True:
time.sleep(2)
cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
data = ''
try:
cursor.execute ("""SELECT * FROM d_requests where processed = 0""")
rows=cursor.fetchall()
print "Waiting for requests..."
except MySQLdb.Error as detail:
print "MySQL Error,",detail
if len(rows) == 0:
cursor.close()
print "No request found..."
continue
for row in rows:
try:
print "Processing request..."
ser = serial.Serial(port=row['port'],
baudrate = row['baud'],
bytesize = row['bytesize'], #8
parity = row['parity'], #serial.PARITY_NONE or N or C
stopbits = row['stopbits'], #1
timeout = row['wait_for_reply'], #0.5
xonxoff = row['sw_flowcontrol'], #0
rtscts = row['hw_flowcontrol']) #0
#Send command to device
ser.write(row['request_string'] + "\r")
#Read device response
data = ser.read(100)#TBD:This value needs to be changeable,not always 100 bytes
ser.close()
print "RESULT : " + data
except (serial.SerialException, AttributeError, NameError) as detail:
data = "Error, could not open port"
print data
except serial.SerialTimeoutException as detail:
data = "Error, port connection timeout" #Error ,detail
print data
except:
data = "Error,Unexpected error"
print data
finally:
#ser.close()
try:
cursor.execute("""UPDATE d_requests SET processed = %s, result_string = %s WHERE id = %s""",(1,data,row['id']))
except MySQLdb.Error as detail:
print "MySQL Error,",detail
#cursor.commit() for innoDB table engines
cursor.close()
if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-example.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
daemon.start()
elif 'stop' == sys.argv[1]:
daemon.stop()
elif 'restart' == sys.argv[1]:
daemon.restart()
elif 'foreground' == sys.argv[1]: #this runs the daemon in the foreground
daemon.run()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)
I have written a web application that interacts with a serial device on /dev/ttyS02.
The problem is my current messaging and queuing solution. Please read below.
Heres the communication bridge between the application and pyserial:
My web application inserts a request record via PHP into a d_requests table in MySQL.
The inserted record's processed column is set to 0.
The inserted record's id is saved in an $id variable and the PHP application enters a
loop state where it will continually check if the d_requests[processed] column = 1 using
the $id as lookup reference.I have a python daemon service that checks every second for records in the
d_requests table where the processed column = 0.
This is considered a new request.(refer to source code - python service)The python service then uses the record's information to connect to the port via
pyserial.The requested action is performed. The record's processed column is then updated to 1
and a few other fields are updated as well.
This marks the record as processed.The PHP control block then exits the loop (Point 1.) and returns the result as json
to the JS application.Where it is presented to the user.
Some points of note
- The serial device is capable of processing 1 request every 250 ms.
- The python daemon service monitors the d_requests table for records where the processed
column = 0 every 1 second. - The only communication my web application has with the python daemon service is the MySQL
DB by inserting requests records in the d_requests table. - I use PHP block code to lookup the request using the inserted id every second to check
if the processed column has been updated to 1.
My Concerns
Single point of failure
When the daemon service is not running serial requests cannot take place
Extreme Resource Usage
I expect about 4-5 requests per second to a serial device. Using the current implementation
for handling messages the db will be working overtime and CPU usage will be high, since the PHP application and python daemon/service will connect and perform queries on the DB and there will be delays with the processing of requests.
Conclusion :
Is there a better way to improve my current messaging and queuing solution?
I think a pyserial web service will work great in this case, where the serial port for eg. is attached to a web socket eg. host:<7000> and I can just send a request via PHP to it and wait for the response back from the web service. Unfortunately I dont know how to do this.
Any ideas?
Thank You
Source code
python service
import sys, time
from daemon import Daemon
import MySQLdb
#Database parameters
config = {"host":"localhost","username":"root","password":"cake","database":"mydb"}
#Check if MySQLdb library is present
try:
conn = MySQLdb.connect(config['host'],config['username'],config['password'],config['database'])
except MySQLdb.Error, e:
print "Error %d: %s" % (e.args[o], e.args[1])
sys.exit(1);
#Check if pyserial library is present
try:
import serial
except ImportError:
print "Error,pySerial module not installed"
sys.exit(1);
#Create DB cursor
#cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
#Declare global variables here
class MyDaemon(Daemon):
def run(self):
while True:
time.sleep(2)
cursor = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
data = ''
try:
cursor.execute ("""SELECT * FROM d_requests where processed = 0""")
rows=cursor.fetchall()
print "Waiting for requests..."
except MySQLdb.Error as detail:
print "MySQL Error,",detail
if len(rows) == 0:
cursor.close()
print "No request found..."
continue
for row in rows:
try:
print "Processing request..."
ser = serial.Serial(port=row['port'],
baudrate = row['baud'],
bytesize = row['bytesize'], #8
parity = row['parity'], #serial.PARITY_NONE or N or C
stopbits = row['stopbits'], #1
timeout = row['wait_for_reply'], #0.5
xonxoff = row['sw_flowcontrol'], #0
rtscts = row['hw_flowcontrol']) #0
#Send command to device
ser.write(row['request_string'] + "\r")
#Read device response
data = ser.read(100)#TBD:This value needs to be changeable,not always 100 bytes
ser.close()
print "RESULT : " + data
except (serial.SerialException, AttributeError, NameError) as detail:
data = "Error, could not open port"
print data
except serial.SerialTimeoutException as detail:
data = "Error, port connection timeout" #Error ,detail
print data
except:
data = "Error,Unexpected error"
print data
finally:
#ser.close()
try:
cursor.execute("""UPDATE d_requests SET processed = %s, result_string = %s WHERE id = %s""",(1,data,row['id']))
except MySQLdb.Error as detail:
print "MySQL Error,",detail
#cursor.commit() for innoDB table engines
cursor.close()
if __name__ == "__main__":
daemon = MyDaemon('/tmp/daemon-example.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
daemon.start()
elif 'stop' == sys.argv[1]:
daemon.stop()
elif 'restart' == sys.argv[1]:
daemon.restart()
elif 'foreground' == sys.argv[1]: #this runs the daemon in the foreground
daemon.run()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你打赌!它们被称为消息队列,它们非常棒。
我最喜欢的是 Gearman,它是由为我们带来 memcached 的同一团队编写的。它有 PHP 和 Python 绑定。与其说它实际上是一个消息队列,不如说它是一个 RPC 服务。无论如何,它允许您从一个环境调用方法并在另一个环境中处理它们。
在这种情况下,您需要用 Python 编写串行接口代码,并让它以 Gearman 函数的形式公开它可以执行的所有操作。它将作为守护进程打开。您的 PHP 代码可以通过 Gearman 调用这些函数。
You bet! They're called message queues, and they are awesome.
My favorite is Gearman, written by the the same team that brought us memcached. It has PHP and Python bindings. It's not actually a message queue so much as an RPC service. Regardless, it will let you call methods from one of your environments and handle them in the other.
In this case, you'd want to write your serial interface code in Python, and have it expose all the things it can do as Gearman functions. It will sit open as a daemon. Your PHP code can call those functions through Gearman.
研究类似的需求。到目前为止发现“ser2net”和“termnetd”守护进程很有帮助。
Researching similar need. Found "ser2net" and "termnetd" daemons helpful so far.