python 2.7 threading GUI and socket - python

Lately I have been working on my python chat project, the server works well but when I use the threading model to run the gui of the client and the select I have a problem with it.
I am able to send data to the server and the server returns the data to the clients but the clients can't print the data.
This is the code of the client :
import socket
import select
from Tkinter import *
import thread
class client(object):
def __init__(self):
self.client_socket = socket.socket()
self.messages =[]
def connect(self):
self.client_socket.connect(('127.0.0.1', 1234))
def getgui(self, window):
self.root = window
def run(self):
while True:
self.rlist, self.wlist, self.xlist = select.select([self.client_socket], [self.client_socket], [])
for current_socket in self.rlist:
data = current_socket.recv(1024)
self.root.print_on_list(data)
def send_to_server(self, word):
self.client_socket.send(word)
class rootgui():
def __init__(self,client_socket):
self.client_socket = client_socket
self.root = Tk()
self.root.geometry('600x700')
self.root.minsize(600, 700)
self.root.maxsize(600, 700)
self.root.title('chat')
self.frame = Frame(self.root)
self.frame.pack()
self.scrollbar = Scrollbar(self.frame)
self.scrollbar.pack(side = RIGHT, fill = Y)
self.chatlist = Listbox(self.frame, yscrollcommand = self.scrollbar.set, width = 80, height = 25 )
self.chatlist.pack(side = LEFT)
self.leftframe = Frame(self.root)
self.leftframe.pack(side = LEFT)
self.send_button = Button(self.leftframe, text = 'send', bg = 'green', padx = 60, pady = 70, command = self.send)
self.send_button.pack()
self.rightframe = Frame(self.root)
self.rightframe.pack(side = RIGHT)
self.text = StringVar()
self.input_box = Entry(self.rightframe, width =55, textvariable = self.text )
self.input_box.pack()
self.scrollbar.config(command = self.chatlist.yview)
def mainloop(self):
self.root.mainloop()
def send(self):
t = self.text.get()
self.client_socket.send_to_server(t)
return
def print_on_list(self, data):
self.chatlist.insert(END, data+'\r\n')
def main():
client_socket = client()
client_socket.connect()
window = rootgui(client_socket)
client_socket.getgui(window)
thread.start_new_thread(window.mainloop())
thread.start_new_thread(client_socket.run())
if __name__ == '__main__':
main()
This is the code of the server:
import socket
import select
class server(object):
''' init function '''
def __init__(self):
self.server_socket = socket.socket()
self.open_client_sockets = []
'''this function send a message to all of the connected clients'''
def send_messages(self, message):
for client_socket in self.open_client_sockets:
client_socket.send(message)
''' this function get a port , it bind the server socket and set the listen to 5 sockets '''
def connection(self):
self.server_socket.bind(('0.0.0.0', 1234))
self.server_socket.listen(5)
''' this function use the select library and read / write from / to the client socket '''
def run(self):
while True:
self.rlist, self.wlist, self.xlist = select.select([self.server_socket]+self.open_client_sockets, self.open_client_sockets, [])
for current_socket in self.rlist:
if current_socket is self.server_socket:
(new_socket, address) = self.server_socket.accept()
self.open_client_sockets.append(new_socket)
print 'new member : ' + str(address)
else:
try:
data = current_socket.recv(1024)
self.send_messages(data)
break
except socket.error:
self.open_client_sockets.remove(current_socket)
print 'Connection with client closed.'
if __name__ == '__main__':
server_socket = server()
server_socket.connection()
server_socket.run()

Related

Threading tkinter serial reading function

I'm making an application that reads serial data coming from the sensors on an arduino board. Problems arise when trying to use the matplotlib.animation class to make a live graph of said data. The GUI widgets become unresponsive when the plotting is taking place. As far as i've understood, making the serial reading process run on its own thread could potentially solve the issue. I'm having trouble understanding how this could be made so that it is compatible with the FuncAnimation-subclass.
def read_serial_data(port, bauds=9600):
s = serial.Serial(port, bauds)
line = s.readline()[0:-2]
return line
def getPorts():
return [port.device for port in serial.tools.list_ports.comports(include_links=False)]
class GUI():
def __init__(self):
self.root = Tk.Tk()
self._fig = plt.figure()
self.root.title('Measurement Dashboard')
self.root.state('normal')
self.root.config(background='#ffffff')
self._canvas = FigureCanvasTkAgg(self._fig, self.root)
self._canvas.get_tk_widget().grid(column = 1, row = 1)
self._canvas.draw()
self._animate = None
self._ax = self._fig.add_subplot(111)
self._ax.yaxis.grid(True, color = 'black', linestyle='--')
self._ax.xaxis.grid(True, color = 'black', linestyle='--')
self._ax.set_xlabel('time')
self._ax.set_ylabel('CO2')
self.filename = Tk.StringVar()
self.entry = ttk.Entry(self.root, textvariable = self.filename)
self.entry.grid(column = 2, row = 2)
self.info_var = Tk.StringVar()
self.info_entry = ttk.Entry(self.root, textvariable = self.info_var)
self.info_entry.grid(column = 2, row = 3)
self.port = Tk.StringVar()
self.ports = getPorts()
self._cb = ttk.Combobox(self.root, textvariable= self.port, values = self.ports)
self._cb.grid(column = 2, row = 1)
self.start_button = Tk.Button(self.root, text = 'Start', command = self.plot)
self.start_button.grid(column = 1, row = 2)
self.save_button = Tk.Button(self.root, text = 'Save info', command = self.save_info)
self.save_button.grid(column = 2, row = 4)
def save_info(self):
global info
info = self.info_var.get()
def start(self):
self.root.mainloop()
def plot(self):
if self._animate is None:
self.scope = Scope(self._ax, self.filename.get())
self._canvas.draw_idle()
self._animate = animation.FuncAnimation(self._fig, self.scope.animate, frames = self.update, interval=2000, blit=False)
def update(self):
line = read_serial_data(self.port.get())
data = line.decode('utf-8')
yield data
time = datetime.now()
duration = time - start_time
measurement = {'time': time, 'dur': duration.seconds, 'CO2': data, 'info': info}
write_csv_line(self.filename.get(), measurement)
self.root.after(10000, self.update)
if __name__ == "__main__":
gui = GUI()
gui.start()
thread = Thread(target=read_serial_data,args=(gui.port,))
thread.start()
You don't really need another thread but can do this using non-blocking IO on th eserial port and make use of the Tkinter after call to manage the poll interval. pyserial provices inWaiting to test if the device has input waiting to be read. If there are bytes waiting, read just those.
Here is an example reader class to read lines from a serial device and post them to the application handler method once a complete line is read.
class Reader(Serial):
def __init__(self, *args, **kwargs):
self.buffer = ''
super(Reader, self).__init__(*args, **kwargs)
def monitor(self, w, interval=10):
n = self.inWaiting()
if n != 0:
data = self.read(n).decode('ascii')
self.buffer = self.buffer + data
ndx = self.buffer.find("\n")
if ndx != -1:
line = self.buffer[:ndx+1]
self.buffer = self.buffer[ndx+1:]
w.after_idle(lambda: w.parse_input(line))
w.after(interval, lambda: self.monitor(w, interval))
Used like:
app = <tkinter application class instance>
reader = Reader(port, baudrate, timeout=0)
reader.flushInput()
reader.monitor(app, 10)
app.mainloop()
In this case, it will call a parse_input method on the app instance whenever a line is read (delimited by a newline).
If you decide to use a thread, then you need a Queue to pass the data to the Tkinter UI thread and must ensure you don't call Tkinter methods from the worker thread.

PyQt crahses when trying to transfer data using sockets

I am trying to make a simple video chat application with 2 participants. Here the JoinClient is the a PyQt UI for entering code and accessing the meeting. This window is then redirected to the CallClient where the actual meeting takes place. I am using cv2.VideoCapture(0) to get a video frame and then using PIL and PyQt I am processing that frame and signalling the Qpixmap of the same. However, I am sending a raw frame to the server, which is then sent to the second user by the server itself. I am doing something similar with audio using pyaudio and audio streams to input and output audio. Before adding the socket programming, the application works just fine, but as I add the socket programming the application after opening the CallClient stops responding. I am unsure as to why this happens or how I could fix it.
client.py
from PyQt5 import QtCore, QtGui, QtWidgets
import meetingui
import joinui
from PIL.ImageQt import ImageQt
from PIL import Image
import cv2
import pyaudio
import network as net
class Worker(QtCore.QObject):
finished = QtCore.pyqtSignal()
cam_signal = QtCore.pyqtSignal(bool)
mic_signal = QtCore.pyqtSignal(bool)
p1video_feed_signal = QtCore.pyqtSignal(QtGui.QPixmap)
p2video_feed_signal = QtCore.pyqtSignal(QtGui.QPixmap)
def __init__(self, parent=None):
QtCore.QObject.__init__(self, parent=parent)
self.leave_call = False
self.camera_status = False
self.mic_status = False
self.audio_interface = pyaudio.PyAudio()
self.chunk = 2048
self.sample_format = pyaudio.paInt16
self.channels = 2
self.fs = 44100
def run(self, name, code):
network = net.Network({'name': name, 'code': code})
person = {}
while not self.leave_call:
# Get self mic data
if self.mic_status:
audio_data = self.stream.read(self.chunk)
person['audio'] = audio_data
else:
person['audio'] = None
# get self camera data
if self.camera_status and self.video_feed.isOpened():
check, self.p1frame = self.video_feed.read()
if check:
self.p1frame = cv2.cvtColor(self.p1frame, cv2.COLOR_BGR2RGB)
self.p1frame = cv2.flip(self.p1frame, 1)
self.PILp1frame = Image.fromarray(self.p1frame).convert('RGB')
self.Qtp1frame = ImageQt(self.PILp1frame)
self.p1video_feed_signal.emit(QtGui.QPixmap.fromImage(self.Qtp1frame))
person['video_frame'] = self.p1frame
else:
person['video_frame'] = None
else:
person['video_frame'] = None
# send self data and receive person2 data
p2 = network.send(person)
if p2:
if p2['audio']:
self.stream.write(p2['audio'])
if p2['video_frame']:
self.PILp2frame = Image.fromarray(p2['video_frame']).convert('RGB')
self.Qtp2frame = ImageQt(self.PILp2frame)
self.p2video_feed_signal.emit(QtGui.QPixmap.fromImage(self.Qtp2frame))
else:
self.p2video_feed_signal.emit(QtGui.QPixmap('Icons\\img_avatar.png'))
else:
break
self.finished.emit()
def leave(self):
self.audio_interface.terminate()
self.leave_call = True
def toggle_cam(self):
if not self.camera_status:
self.video_feed = cv2.VideoCapture(0)
self.camera_status = True
else:
self.camera_status = False
self.video_feed.release()
self.p1video_feed_signal.emit(QtGui.QPixmap('Icons\\img_avatar.png'))
self.cam_signal.emit(self.camera_status)
def toggle_mic(self):
if not self.mic_status:
self.stream = self.audio_interface.open(format=self.sample_format,
channels=self.channels,
rate=self.fs,
frames_per_buffer=self.chunk,
input=True,
output=True)
self.mic_status = True
else:
self.mic_status = False
self.stream.stop_stream()
self.stream.close()
self.mic_signal.emit(self.mic_status)
class CallClient(QtWidgets.QWidget, meetingui.Ui_MeetingWindow):
stop_signal = QtCore.pyqtSignal()
toggle_cam_signal = QtCore.pyqtSignal()
toggle_mic_signal = QtCore.pyqtSignal()
def __init__(self, code, name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
self.P1_name = name
self.MeetCode = code
self.setWindowTitle(f'Video Call App (Meeting Code - {code})')
# Signals and Slots
self.thread = QtCore.QThread()
self.worker = Worker()
self.stop_signal.connect(self.worker.leave)
self.toggle_cam_signal.connect(self.worker.toggle_cam)
self.toggle_mic_signal.connect(self.worker.toggle_mic)
self.worker.moveToThread(self.thread)
self.thread.started.connect(lambda: self.worker.run(self.P1_name, self.MeetCode))
self.worker.cam_signal.connect(lambda status: self.handleCam(status))
self.worker.mic_signal.connect(lambda status: self.handleMic(status))
self.worker.p1video_feed_signal.connect(lambda video_feed: self.setP1Frames(video_feed))
self.worker.p2video_feed_signal.connect(lambda video_feed: self.setP2Frames(video_feed))
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.finished.connect(self.close)
self.thread.start()
self.leaveBtn.clicked.connect(self.stop_thread)
self.cameraBtn.clicked.connect(self.toggle_cam)
self.micBtn.clicked.connect(self.toggle_mic)
def stop_thread(self):
self.stop_signal.emit()
self.close()
def toggle_cam(self):
self.toggle_cam_signal.emit()
def toggle_mic(self):
self.toggle_mic_signal.emit()
def handleCam(self, cam_status):
if cam_status:
cam_icon = QtGui.QIcon()
cam_icon.addPixmap(QtGui.QPixmap("Icons\\icons8-camera-96.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.cameraBtn.setIcon(cam_icon)
self.cameraBtn.setStyleSheet(
"border:none;border-radius: 35px;padding: 10px;background-color: rgb(255, 255, 255);")
else:
cam_icon = QtGui.QIcon()
cam_icon.addPixmap(QtGui.QPixmap("Icons\\no-cam-icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.cameraBtn.setIcon(cam_icon)
self.cameraBtn.setStyleSheet(
"border:none;border-radius: 35px;padding: 10px;background-color: rgb(204, 0, 0);")
def handleMic(self, mic_status):
if mic_status:
mic_icon = QtGui.QIcon()
mic_icon.addPixmap(QtGui.QPixmap("Icons\\icons8-microphone-96.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.micBtn.setIcon(mic_icon)
self.micBtn.setStyleSheet(
"border:none;border-radius: 35px;padding: 10px;background-color: rgb(255, 255, 255);")
else:
mic_icon = QtGui.QIcon()
mic_icon.addPixmap(QtGui.QPixmap("Icons\\no-mic-icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.micBtn.setIcon(mic_icon)
self.micBtn.setStyleSheet(
"border:none;border-radius: 35px;padding: 10px;background-color: rgb(204, 0, 0);")
def setP1Frames(self, pixmap):
self.Person1_Self.setPixmap(pixmap)
def setP2Frames(self, pixmap):
self.Person2_Opposite.setPixmap(pixmap)
class JoinClient(QtWidgets.QWidget, joinui.Ui_JoinClient):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.joinbtn.clicked.connect(self.connect_to_meeting)
self.x_btn.clicked.connect(self.btn_close_clicked)
self.minus_btn.clicked.connect(self.btn_minus_clicked)
def mousePressEvent(self, event):
self.start = self.mapToGlobal(event.pos())
self.pressing = True
def mouseMoveEvent(self, event):
if self.pressing:
self.end = self.mapToGlobal(event.pos())
self.movement = self.end - self.start
self.setGeometry(self.mapToGlobal(self.movement).x(),
self.mapToGlobal(self.movement).y(),
self.width(),
self.height())
self.start = self.end
def mouseReleaseEvent(self, QMouseEvent):
self.pressing = False
def btn_close_clicked(self):
self.close()
def btn_minus_clicked(self):
self.showMinimized()
def connect_to_meeting(self):
print(self.username_edit.text())
print(self.code_edit.text())
self.meetClient = CallClient(self.code_edit.text(), self.username_edit.text())
self.meetClient.show()
self.close()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main_client = JoinClient()
main_client.show()
sys.exit(app.exec_())
network.py
import socket
import pickle
class Network:
def __init__(self, data: dict):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server = "192.168.1.38"
self.port = 5555
self.addr = (self.server, self.port)
self.connect(data)
def connect(self, data: dict):
try:
self.client.connect(self.addr)
self.client.send(pickle.dumps(data))
print('connected :D')
except:
pass
def send(self, data):
try:
self.client.send(pickle.dumps(data))
return pickle.loads(self.client.recv(2048*500))
except socket.error as e:
print(e)
server.py
import socket
import threading
from models import Meeting
import pickle
server = "192.168.1.38"
port = 5555
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server, port))
except socket.error as e:
str(e)
s.listen(2)
print("Waiting for a connection, Server Started")
meetings = []
def threaded_client(conn):
initials = pickle.loads(conn.recv(2048))
currentMeeting = None
currentMeetingIndex = 0
p = 'p1'
for meeting in meetings:
if initials['code'] == meeting.code:
currentMeeting = meeting
p = 'p2'
currentMeetingIndex = meetings.index(currentMeeting)
meetings[currentMeetingIndex].P2 = {'name': initials['name'], 'video_frame': None, 'audio': None}
if not currentMeeting:
currentMeeting = Meeting({'name': initials['name'], 'video_frame': None, 'audio': None}, {'name': None, 'video_frame': None, 'audio': None}, initials['code'])
meetings.append(currentMeeting)
currentMeetingIndex = meetings.index(currentMeeting)
reply = ""
while True:
try:
data = pickle.loads(conn.recv(2048*500))
if not data:
print("Disconnected")
if p == 'p1':
meetings[currentMeetingIndex].P1 = {'name': None, 'video_frame': None, 'audio': None}
else:
meetings[currentMeetingIndex].P2 = {'name': None, 'video_frame': None, 'audio': None}
break
else:
if p == 'p1':
meetings[currentMeetingIndex].P1['video_frame'] = data['video_frame']
meetings[currentMeetingIndex].P1['audio'] = data['audio']
reply = meetings[currentMeetingIndex].P2
else:
meetings[currentMeetingIndex].P2['video_frame'] = data['video_frame']
meetings[currentMeetingIndex].P2['audio'] = data['audio']
reply = meetings[currentMeetingIndex].P1
print("Received: ", data)
print("Sending : ", reply)
conn.sendall(pickle.dumps(reply))
except:
break
if not currentMeeting.P1['name'] and not currentMeeting.P2['name']:
meetings.remove(currentMeeting)
print('meet ended')
print("Lost connection")
print(meetings)
conn.close()
while True:
conn, addr = s.accept()
print("Connected to:", addr)
if conn:
new_thread = threading.Thread(target=threaded_client, args=(conn,))
new_thread.start()
One of the inconvenient things about TCP is that it is a streaming protocol, not a packet protocol. The bytes get transferred eventually, but it doesn't honor your packet boundaries. If you send a 2048-byte chunk and a 1024-byte chunk, depending on network traffic you might receive 500 bytes, then 1000 bytes, then 600, then the last 972. You cannot assume that you are receiving a complete pickle, nor that you are receiving only one -- they could be combined. You must send some kind of header to allow the other end to reconstruct the packets.

UDP messages are sent faster than they are received

I've been working hours to send video frames through a UDP socket and this is what I've done so far:
Client side: sends the captured video and then receives it and rebuilds the frame and displays it on tkinter
import socket
from tkinter import *
from PIL import ImageTk, Image
import cv2
import numpy
import threading
IP = "127.0.0.1"
PORT = 8080
my_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
my_socket.connect((IP, PORT))
root = Tk()
main_label = Label(root)
main_label.grid()
cap = cv2.VideoCapture("video.mp4")
LEN = 61440
DIV = 60
def send_msg(frame):
for i in range(DIV):
my_socket.sendto(frame[i*LEN:(i+1)*LEN], (IP, PORT))
def receive_msg():
while True:
data = b""
while len(data) != (LEN * DIV):
msg, add = my_socket.recvfrom(LEN)
data += msg
create_frame(data)
def create_frame(data):
numpy_img = numpy.frombuffer(data, dtype=numpy.uint8)
numpy_img = numpy_img.reshape(720, 1280, 4)
img = Image.fromarray(numpy_img)
tk_img = ImageTk.PhotoImage(image=img)
main_label.configure(image=tk_img)
main_label.tk_img = tk_img
def video_stream():
ret, frame = cap.read()
colored_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
bytes_frame = colored_frame.tobytes()
send_msg(bytes_frame)
main_label.after(50, video_stream)
def main():
t = threading.Thread(target=receive_msg)
t.start()
video_stream()
root.mainloop()
if __name__ == '__main__':
main()
Server side: sends everything it receives
import socket
IP = "0.0.0.0"
PORT = 8080
LEN = 61440
def main():
server_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
server_socket.bind((IP, PORT))
while True:
msg, add = server_socket.recvfrom(LEN)
server_socket.sendto(msg, add)
if __name__ == '__main__':
main()
the problem is that the video is displayed not like the regular video:
Regular:
Result:
as you can see, the parts of the frame itself are messy and I don't really know a possible way to fix it...

tkinter and multiple threads

I am trying to start a function with a new thread and everytime i start the function, the tkinter application opens up again. For me to see the function running i need to quit the new application that opened and then it starts. Is there something in my code that is calling the application again and not allowing my startReceive function to run instantly when i start the thread?
import tkinter as tk
from udpTransfer1 import UdpClass
from threading import Thread
from tkinter import messagebox
import multiprocessing, time, signal
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.alert = ''
self.pack()
self.alive = False
self.create_widgets()
self.c = UdpClass()
self.threadExists= False
self.st = None
def create_widgets(self):
# 1 button
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Save UDP"
self.hi_there["command"] = self.run
self.hi_there.pack(side="top")
# 2 button
self.b2 = tk.Button(self)
self.b2["text"] = "Stop UDP"
self.b2["command"] = self.b2Action
self.b2.pack(side="top")
# 3 button
self.quit = tk.Button(self, text="QUIT", fg="red")
self.quit["command"] = self.kill
self.quit.pack(side="bottom")
def kill(self):
if self.threadExists == True:
# Alert Box
# self.alert = messagebox.showinfo("ALERT").capitalize()
self.alert = messagebox._show(None,'UDP has to be stopped first!')
else:
root.destroy()
def run(self):
# self.st = Thread(target=self.c.startReceive)
# self.st = multiprocessing.Process(target=self.c.startReceive)
self.st = multiprocessing.Process(target=startReceive)
self.st.start()
if (self.st.is_alive()):
print("Thread open")
self.threadExists = True
def b2Action(self):
if self.threadExists:
# self.c.terminate()
terminate()
self.st.terminate()
time.sleep(.1)
if not(self.st.is_alive()):
print("Thread Killed")
self.threadExists = False
else :
self.alert = messagebox._show(None, 'No Detection of UDP Running!')
def startReceive():
print('started')
try:
isRunning = True
# csvfile = open(self.filename, 'w')
# spamwriter = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
# start_time = time.time()
while isRunning:
print('done')
time.sleep(1)
except:
print('out')
def terminate():
# self.socket.close()
# isRunning = False
print('stopped')
root = tk.Tk()
app = Application(master=root)
app.master.title("UDP Saving")
app.master.geometry('200x200')
app.master.maxsize(200, 500)
app.mainloop()
Not 100% sure, but this might be the issue:
def run(self):
# self.st = Thread(target=self.c.startReceive)
# self.st = multiprocessing.Process(target=self.c.startReceive)
self.st = multiprocessing.Process(target=startReceive)
self.st.start()
if (self.st.is_alive()):
print("Thread open")
self.threadExists = True
I think You should put self.threadExists = True inside previous if.
def run(self):
# self.st = Thread(target=self.c.startReceive)
# self.st = multiprocessing.Process(target=self.c.startReceive)
self.st = multiprocessing.Process(target=startReceive)
self.st.start()
if (self.st.is_alive()):
print("Thread open")
self.threadExists = True

Stop Threading when clossing the app

Can I close the DataCom thread before TKinter GUI exit? When I run the code into WING IDE closing the GUI the DataCom still running receiving packets from center. I tried to find something similar example none of them work.
from Tkinter import Tk, N, S, W, E, BOTH, Text, Frame,Label, Button,Checkbutton, IntVar,Entry
import socket
import sys
import os
import time
import datetime
from threading import Thread
data = ''
def timeStamped(fmt='%Y-%m-%d-%H-%M-%S_{fname}'):
return datetime.datetime.now().ctime()
def get_constants(prefix):
"""Create a dictionary mapping socket module constants to their names."""
return dict( (getattr(socket, n), n)
for n in dir(socket)
if n.startswith(prefix)
)
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.friend_check = IntVar()
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Home.local")
self.PoolLabel = Label (text = "Pool Temperature:")
self.PoolLabel.grid(row=0,column=0,columnspan=2, sticky=W)
self.BasementLabel = Label (text = "Basement Conditions:")
self.BasementLabel.grid(row=3,column=0,columnspan=2, pady =10)
try:
datalist=data.split(':')
print datalist
self.cl_label=Label(text="")
self.cl_label.config(text=datalist[0].split(', ',1)[1])
self.cl_label.grid(row=1,column=0,columnspan=2,sticky='EW')
self.baselabelT=Label(text="")
self.baselabelT.config(text=datalist[1])
self.baselabelT.grid(row=4,column=0,columnspan=2,sticky='EW')
self.baselabelH=Label(text="")
self.baselabelH.config(text=datalist[2])
self.baselabelH.grid(row=5,column=0,columnspan=2,sticky='EW')
except IndexError:
datalist = 'null'
self.btn_Exit = Button(text="Exit", command = '')
self.btn_Exit.grid(row=10,column=2)
#self.update()
self.after(1000, self.initUI)
class DataCom(Thread):
def __init__(self, val):
Thread.__init__(self)
self.val = val
def run(self):
global data
families = get_constants('AF_')
types = get_constants('SOCK_')
protocols = get_constants('IPPROTO_')
# Create a TCP/IP socket
sock = socket.create_connection(('localhost', 10000))
print >>sys.stderr, 'Family :', families[sock.family]
print >>sys.stderr, 'Type :', types[sock.type]
print >>sys.stderr, 'Protocol:', protocols[sock.proto]
print >>sys.stderr
while True:
try:
# Send flag
message = 'INFO'
print >>sys.stderr, 'sending "%s" Length: %s' % (message,len(message))
sock.sendall(message)
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = sock.recv(1024)
amount_received += len(data)
if len(data) != 0:
print >>sys.stderr, 'Server received %s %s:Length %s' % (timeStamped(), data, len(data))
else:
sock.close()
print >>sys.stderr, 'No more data, closing socket'
break
if not data:
break
finally:
time.sleep(1)
def main():
myThread = DataCom(1)
myThread.setName('DataComThread')
myThread.start()
root = Tk()
root.geometry("600x450+900+300")
root.resizable(0,0)
app = Example(root)
root.config(background = "#FFFFFF") # ui debug
root.mainloop()
if __name__ == '__main__':
main()

Categories