如何创建一个pyserial网络服务?

0 投票
2 回答
2192 浏览
提问于 2025-04-16 13:28

我写了一个网页应用,它可以和一个串口设备(在/dev/ttyS02上)进行互动。现在的问题是我目前的消息和排队解决方案。请看下面的内容。

这是应用程序和pyserial之间的通信桥梁:

  • 我的网页应用通过PHP把请求记录插入到MySQL的d_requests表中。插入的记录的processed列被设置为0。插入记录的id保存在一个变量$id中,然后PHP应用进入一个循环状态,不断检查d_requests表中对应的processed列是否变为1。

  • 我有一个Python守护进程,每秒检查一次d_requests表中processed列为0的记录。这被视为一个新请求。(请参考源代码 - python服务)

  • 这个Python服务会使用记录中的信息通过pyserial连接到串口。

  • 请求的操作会被执行。然后记录的processed列会更新为1,同时其他几个字段也会被更新。这就标记了这条记录为已处理。

  • PHP控制块随后退出循环(第一点),并将结果以json格式返回给JS应用,最后呈现给用户。

需要注意的一些点

  • 这个串口设备每250毫秒可以处理一个请求。
  • Python守护进程每秒监控一次d_requests表中processed列为0的记录。
  • 我的网页应用和Python守护进程之间唯一的通信方式是通过MySQL数据库,插入请求记录到d_requests表中。
  • 我每秒使用PHP代码块通过插入的id查找请求,以检查processed列是否更新为1。

我的担忧

单点故障

当守护进程没有运行时,串口请求就无法进行。

极高的资源使用

我预计每秒会有4-5个请求发送到串口设备。使用当前的消息处理方式,数据库会超负荷运转,CPU使用率也会很高,因为PHP应用和Python守护进程会连接并对数据库执行查询,这会导致请求处理的延迟。

结论:有没有更好的方法来改善我目前的消息和排队解决方案?我认为一个pyserial网络服务在这种情况下会很好,比如说串口连接到一个网络套接字(例如:host:<7000>),我可以通过PHP发送请求,然后等待网络服务的响应。不幸的是,我不知道该怎么做。

有什么想法吗?

谢谢

源代码

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)

2 个回答

0

我在研究类似的需求。到目前为止,发现“ser2net”和“termnetd”这两个程序很有帮助。

1

有没有更好的办法来改善我现在的消息传递和排队解决方案?

当然有!它们叫做消息队列,非常棒。

我最喜欢的是Gearman,它是由和我们一起开发memcached的团队制作的。它有PHPPython的接口。其实它不完全是一个消息队列,更像是一个远程过程调用(RPC)服务。不过无论如何,它可以让你在一个环境中调用方法,然后在另一个环境中处理这些方法。

在这种情况下,你可以用Python编写你的串行接口代码,并把它能做的所有事情作为Gearman函数暴露出来。它会作为一个守护进程一直运行。你的PHP代码可以通过Gearman调用这些函数。

撰写回答