python - 如何欺骗 Thread.start() 在 python 中多次运行
问题描述
介绍
我正在构建一个 p2pvideo 通话应用程序。
从接到电话的一方
我让kivy主循环作为一个线程运行,另一个线程slistner_bind_thread.start()(一个socket.bind函数)监听调用并返回一个拾取报价或拒绝报价,如果它拾取报价它启动另一个线程sstream_bind_thread .start() 哪个 cv2capture 和打包发送提要(socket.bind)。
从打电话的那一侧
我有与另一个线程 scall_CON_thread.start() (socket.connect) 的线程运行相同的 kivy 主循环,该线程以呼叫按钮开始,如果它被拾取报价,则等待对方的取货报价或拒绝调用另一个线程 feed_CON_thread.start() 来审查 opencv2 数据包。
问题
当我拨打电话时,一切都按预期工作,但是当挂断电话并再次拨打电话时,我明白线程不能多次启动。如果我尝试使用其他任何东西,则 gui 显然会被窃听。我有一些想法,但我不知道它们是否可行,如果有人可以提出建议,请至少发表评论。
这是main.py
import socket
import gi
gi.require_version('Gst', '1.0')
import kivy
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty, NumericProperty, ReferenceListProperty
from kivy.graphics.texture import Texture
from kivy.core.camera import Camera
from kivy.graphics import *
import time
import os
from pathlib import Path
import cv2
import struct
import threading
import pickle
Builder.load_file('the.kv')
##########go to line 233 and 240
################################ GLOBAL VARIABLAS BEGIN #######################
######## PORTS ############
sfeed_CON_port = 2430
slistner_bind_port = 1330
sstream_bind_port = 2430
scall_CON_port = 1330
###################### ################# #########
action = ''
endcall = False
endcall_string = ''
myip = ''
sfeed_cv_frame_recieve = None
incall_add = 'nocalls'
outcall_add = ''
################################ GLOBAL VARIABLS END #########################
def feedconnect():
global outcall_add, sfeed_CON_port, endcall ########### addr conn from listenr
global sfeed_cv_frame_recieve
try:
sfeed_CON_ad = outcall_add
sfeed_CON = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sfeed_CON.connect((sfeed_CON_ad, sfeed_CON_port))
data = b""
payload_size = struct.calcsize("Q")
while endcall == False:
while len(data) < payload_size:
packet = sfeed_CON.recv(4*1024)
if not packet: break
data+=packet
packed_msg_size = data[:payload_size]
data =data[payload_size:]
msg_size = struct.unpack("Q", packed_msg_size)[0]
while len(data) < msg_size:
data+=sfeed_CON.recv(4*2024)
frame_data = data[:msg_size]
data =data[msg_size:]
frame = pickle.loads(frame_data)
sfeed_cv_frame_recieve = frame
key = cv2.waitKey(1) & 0xFF
if endcall == True:
print(endcall_string + ' closing feedconnect() socket')
sfeed_CON.close()
break
sfeed_CON.close()
except Exception as e:
print("client: " + outcall_add + 'disconnected ')
sfeed_CON_thread = threading.Thread(target = feedconnect) ####### THREAD
def callconnect():
global outcall_add, scall_CON_port
scall_CON_ad = outcall_add
scall_CON = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scall_CON.connect((scall_CON_ad, scall_CON_port))
print('callconnect is waiting for an answer from :' + scall_CON_ad + ' on port: ' + str(scall_CON_port))
time.sleep(15)
answer = scall_CON.recv(4*1024)
decoded_answer = answer.decode("utf-8")
if decoded_answer == 'decilned':
print(decoded_answer)
elif decoded_answer == 'picked up' :
print(decoded_answer)
f = True ############ to check
#feedconnect()
sfeed_CON_thread.start()
print(f)
else:
print(decoded_answer)
scall_CON.close()
scall_CON_thread = threading.Thread(target = callconnect) #### THREAD
def streambind():
global myip, sstream_bind_port
sstream_bind_ad = myip
sstream_bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sstream_bind.bind((sstream_bind_ad, sstream_bind_port))
print('myip is : ' + myip + ' from streambind() ' )
sstream_bind.listen(5)
sstream_bind_sclient, sstream_bind_sclient_ad = sstream_bind.accept()
if sstream_bind_sclient:
opcv_vid = cv2.VideoCapture(0)
while (opcv_vid.isOpened()):
try:
img, frame = opcv_vid.read()
pickled_frame = pickle.dumps(frame)
struct_pickled_frame = struct.pack("Q", len(pickled_frame)) + pickled_frame
sstream_bind_sclient.sendall(struct_pickled_frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
slistner_bind_sclient.close()
except:
endcall = True
endcall_string ='endcall'
print(endcall_string, endcall)
sstream_bind.close()
break
#sstream_bind_sclient.close() ############ hint i am closing only the client
sstream_bind_thread = threading.Thread(target = streambind) #### THREAD
def listnerbind():
global myip, slistner_bind_port, incall_add
global action
host_name = socket.gethostname()
myip = socket.gethostbyname(host_name + ".local")
slistner_bind_ad = myip
slistner_bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
slistner_bind.bind((slistner_bind_ad, slistner_bind_port))
slistner_bind.listen(10)
print('listnerbind() on thread')
print('listning for calls in: ' + slistner_bind_ad + ' on port: ' + str(slistner_bind_port))
while True:
slistner_bind_sclient, slistner_bind_sclient_ad = slistner_bind.accept()
###### block note start ###
#### the incall_add should be a list for multiple incalls at once #####
incall_add = str(slistner_bind_sclient_ad[0])
###### block note end ####
print('incall from: ' + incall_add + ' at port: ' + str(slistner_bind_port))
time.sleep(15) ##### needs to be edited later #########
if action == '':
slistner_bind_sclient.send(bytes('no answer',"utf-8"))
elif action == 'picked up':
sstream_bind_thread.start()
slistner_bind_sclient.send(bytes(action,"utf-8"))
elif action == 'declined':
slistner_bind_sclient.send(bytes(action,"utf-8"))
slistner_bind_thread = threading.Thread(target = listnerbind)
class fscreen(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def on_touch_down(self, touch):
if touch.x !=0:
theapp.screenm.current = "secondscreen"
class secscreen(Widget):
waiter = StringProperty()
callerid = StringProperty()
def __init__(self,**kwargs):
super().__init__(**kwargs)
global outcall_add
Clock.schedule_interval(self.callcheck, 0.5)
def callcheck(self, *args):
global incall_add
self.waiter = incall_add
self.callerid = incall_add
def decline(self):
global action
action = "declined"
def pickup(self):
global action
action = "picked up"
theapp.screenm.current = "thirdscreen"
def call(self):
global callconnect
global outcall_add
self.ip = self.ids.ipcall.text
outcall_add = self.ip
theapp.screenm.current = "thirdscreen"
if outcall_add != '':
print('')
#### note start sstreamer_bind_thread should also start but i dont have another camera###
#callconnect()
scall_CON_thread.start()
########## note end ########
class thscreen(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
global sfeed_cv_frame_recieve, endcall
Config.set('graphics', 'resizable', True)
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '800')
#######################
Clock.schedule_interval(self.feedupdate, 0.01)
def feedupdate(self, dt): # MULTIPLE USERS NEDSS MORE WORK OF POS AND SIZE AFTER SOCKETS
global sfeed_cv_frame_recieve, endcall
############## note begin sfeed_cv_frame_recieve is converted to texture ############
if sfeed_cv_frame_recieve is not None and endcall == False:
self.frame = sfeed_cv_frame_recieve
buf1 = cv2.flip(self.frame, 0)
buf = buf1.tostring()
image_texture = Texture.create(
size=(self.frame.shape[1], self.frame.shape[0]), colorfmt='bgr')
image_texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
self.texture = image_texture
with self.canvas:
Rectangle(texture=self.texture, pos=(self.pos[0], self.pos[1]+(self.size[1]*0.1)), size=(self.size[0],self.size[1]*0.9))
###################### note end ##############
elif endcall == True:
theapp.screenm.current = "secondscreen"
def hangup(self):
global endcall
endcall = True
endcall_string = 'endcall'
print(endcall_string)
theapp.screenm.current = "secondscreen"
class theapp(App):
def build(self):
self.screenm = ScreenManager() #(transition=FadeTransition())
self.fscreen = fscreen()
screen = Screen(name = "first screen")
screen.add_widget(self.fscreen)
self.screenm.add_widget(screen)
self.secscreen = secscreen()
screen = Screen(name = "secondscreen")
screen.add_widget(self.secscreen)
self.screenm.add_widget(screen)
self.thscreen = thscreen()
screen = Screen(name = "thirdscreen")
screen.add_widget(self.thscreen)
self.screenm.add_widget(screen)
return self.screenm
if __name__ == "__main__":
theapp = theapp()
slistner_bind_thread.start() ########### LISTING THREAD
threading.Thread(target = theapp.run()) ################ GUI APP THREAD
这是.kv文件
<fscreen>
Label:
text: '0I Mechanics'
font_size: root.width*0.05
pos: root.width*0.4, root.height*0.8
<secscreen>
TextInput:
id: ipcall
hint_text: 'Ip'
width: root.width*0.3
height: root.height*0.05
pos: root.width*0.4, root.height*0.8
Button:
text: 'call'
width: root.width*0.3
height: root.height*0.05
pos: root.width*0.4, root.height*0.7
on_press: root.call()
Label:
text: root.callerid
font_size: root.width*0.02
pos: root.width*0.4, root.height*0.4
Button:
text: 'pickup'
width: root.width*0.2
height: root.height*0.05
disabled: True if root.waiter == 'nocalls' else False
pos: root.width*0.5, root.height*0.3
on_press: root.pickup()
Button:
text: 'decline'
width: root.width*0.2
height: root.height*0.05
disabled: True if root.waiter == 'nocalls' else False
pos: root.width*0.3, root.height*0.3
on_press: root.decline()
<thscreen>
Widget:
Button:
text: 'hangup'
width: root.width*0.2
height: root.height*0.05
pos: root.width*0.45, root.height*0.01
on_press: root.hangup()
解决方案
推荐阅读
- javascript - Ajax 发布响应包含 html
- java - 如何从我的工作队列任务中获取结果?
- django - 正确的 DRF 过滤器列表视图端点以按 id 返回多个对象
- jquery - 在页面中初始化许多光滑的轮播
- asp.net - 更新面板影响菜单元素
- c# - 使用 While 循环返回程序的起点
- java - FragmentStatePagerAdapter 无法处理大量片段
- .htaccess - 匹配目录名和变量的 Htaccess 重定向 [F]
- java - java 8持续时间“ofSeconds”与“withSeconds”
- polymorphism - 如何要求抽象类的子类作为方法中的参数