用的yolov5,作者自己寫的loadStream函數就是依據 streams.txt裡面的rtsp流地址列表來新建線程,然後實現多路監控的。
大體就是這個圖裡面說的,我已經是為了個整體業務,去小改了這個loadStreams方法,將那些可用的rtsp流地址保存到一個新的list裡面,然後再新建線程。
如何檢驗可用與否,就是用opencv VideoCapture.isOpened() 慢慢去試,連不上就剔除
上面這個流程,是蠢(還想著定時任務,隔一會重啟一下服務器,其實就是潛意識裡,想用最直接(不動腦子)的方法糊弄這個問題)。跟老師一說,老師也是說,還是改成觸發器吧。拖了十天了,今天趁著還沒有干別的事情,腦子還能轉起來,來學一下。
監聽數據庫,然後 讀寫最新數據庫信息到文件,然後利用文件重新啟動服務器。
再去找博客的時候,(我其實之前是找了一些了的),但大多都是對數據庫進行輪詢,也就是和我上面的定時任務差不多了。可我想要的是觸發器,只有當數據庫改變的時候,才會執行,這樣才叫觸發嘛,一直盯著,那叫監控。
然後就看到了這條
確實,那思路就從監聽數據庫 轉變為 用mysql的觸發器然後生成的日志文件(只生成rtsp地址那一列變動的日志),然後再用python的watchdog(這個是輪子Python 監控文件增加、修改、刪除等變化)監聽這個日志文件。 這樣就不用監聽數據庫了,變成了監聽文件。(主要是同事的數據庫連起來很慢,所以能不監聽就不監聽。)
另外一個想法,想著能不能通過mysql的觸發器,直接調用python服務重啟的腳本。這就牽扯到,這個腳本是不是也要放到同事數據庫所在的那台機子上。如果是我這個想法的話,那我上面需要監聽的那個日志文件,肯定也是在數據庫的本機地址上生成的呀,可是我的服務器是部署在autodl的docker裡面的,這兩個又要怎麼互通呢?
好麻煩,要不就 輪詢數據庫得了。
後期要是這個東西真的要上線的話,那數據庫肯定也是在服務器上的吧。mysql部署在docker那就是說日志文件和我項目的代碼是在一個地方的。
如果是一個地方的話,那自己訪問自己肯定很快的呀,輪詢是可以的;或者然後設定觸發器,監控觸發器生成的文件也是可以的;或者觸發器觸發然後調用python重啟腳本也是可以的。
那暫時不知道未來是什麼情況,就把上述可行的路子都看一下。
寫腳本 輪詢 寫的挺好,羅列了兩種需要監聽的類型——新增和改變
我業務裡面也主要就是處理新增的那些數據,如何將它們加入到streams.txt,所以我就可以在輪詢的回調方法那裡寫“將數據寫入streams.txt的文件操作”。
我把他這個代碼排版好了之後,就是如下:
import os
import sys
import time
import threading
import pickle
import pymysql
class BaseListener(object):
# 使用一個線程啟動監聽
def __init__(self):
self.checkpoint = 0
self.stop_flag = True
self.listen_thread = threading.Thread(name="Listener", target=self.do_listen)
self.listen_thread.start()
def start(self):
self.stop_flag = False
def stop(self):
self.stop_flag = True
def set_checkpoint(self, v):
# 設置監聽的斷點,如果需要可以持久存儲在磁盤上
self.checkpoint = v
def get_checkpoint(self):
return self.checkpoint
def do_listen(self):
filename = 'utils/streams.txt'
with open(filename, 'w') as f:
f.write('')
cnt=0
while True:
if not self.stop_flag:
conn = pymysql.connect(host="localhost", user="root", password="123456", charset='utf8')
# 監聽用sql語句,應當以id倒排,需要使用 WHERE id > {CHECK_POINT}進行篩選,如
# sql = "SELECT * FROM a WHERE id>{CHECK_POINT} ORDER BY id DESC"
cursor = conn.cursor()
sql = "SELECT id,monitor_name FROM `fall`.`monitor` WHERE id>{CHECK_POINT}"
checkpoint = self.get_checkpoint()
sql_listen = sql.replace("{CHECK_POINT}", str(checkpoint))
# fetchall為讀取全部記錄的語句
cursor.execute(sql_listen)
# 獲取所有記錄列表
results = cursor.fetchall()
#記錄最後一個游標
rec_id =""
if(len(results)!=0):
cnt += len(results)
rec_id = self.callback(results,cnt)
self.set_checkpoint(rec_id)
# 關閉數據庫連接
cursor.close()
conn.close()
# 根據情況設置輪詢時間
time.sleep(1)
def callback(self,data):
filename = 'utils/streams.txt'
# 這是do_listen調用的一個回調函數,把數據傳過來處理,在子類中實現
with open(filename, 'a+') as f:
f.write(data)
class BaseMonitor(object):
""" 監聽數據變化的基類 """
def __init__(self):
self.prev_data = None
self.stop_flag = True
self.monitor_thread = threading.Thread(name="Monitor", target=self.do_monitor)
self.monitor_thread.start()
def start(self):
self.stop_flag = False
def stop(self):
self.stop_flag = True
def do_monitor(self):
while True:
if not self.stop_flag:
self.execute(self.extra_sql)
data = self.fetchall(self.base_sql)
if data:
str_data = pickle.dumps(data)
if str_data != self.prev_data:
self.callback(data)
self.prev_data = str_data
def callback(self, dictdata):
# 這是do_monitor調用的一個回調函數,把數據傳過來處理,在子類中實現
print
"Should be implemented in subclasses!"
class Listener(BaseListener):
def callback(self, data,cnt):
filename = 'utils/streams.txt'
if(cnt!=len(data)):
p = sys.executable
os.execl(p, p, *sys.argv)
rec_id=""
# 這是do_listen調用的一個回調函數,把數據傳過來處理,在子類中實現
with open(filename, 'a+') as f:
for i, row in enumerate(data):
ip = row[1]
if(i==0):
f.write(ip)
else:
f.write('\n'+ip)
rec_id = row[0]
return rec_id
class MonitorTest(BaseMonitor):
def callback(self, dictdata):
print
"Monitor:",dictdata
if __name__ == "__main__":
ad = Listener()
ad.start()
其余兩個 有機會再寫吧監控日志 觸發器調用腳本
然後這個重啟功能,在這篇博客表頭有提到,所以在pycharm上面無法成功演示,但在服務器linux上應該就ok了。
windows下任務管理器中運行在pycharm或者其他ide下的python應用程序,我們知道此時pycharm是進程,而運行的.py文件是線程功能,這樣如果監測進程實現起來比較繁瑣,因此可以將.py文件轉換為.exe文件使用pyinstaller將py文件轉換成.exe可執行文件,這樣在windows直接執行.exe文件*
所以任務就這樣了,最後還是選擇了,輪詢的方法,然後每次都是講streams.txt文檔清空,重新寫入,當第一次這批寫入之後的下一次,就重啟。(因為我要重啟,重啟之後,那些記錄的標記呀,都沒有了,在博客案例裡面,還指望這個標記去記錄,然後方便下一次查詢)
所以我就是把 記錄的數量記錄了一下,如果數量增加,我就重啟。《——對 我已經變成這個邏輯了
okokok
煩死了,自己太垃了,這麼個小功能,吭哧了四五個小時。