Client Code:
import tkinter as tk
from tkinter.filedialog import asksaveasfilename
import tkinter.messagebox
from PIL import Image
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
def ConnectToServer():
HOST=entry.get()
PORT=65432
test=True
try:
s.connect((HOST,PORT))
except Exception as e:
tkinter.messagebox.showerror(title="Error",message="Error")
test=False
if test:
tkinter.messagebox.showinfo(title="Noti",message="Connect Successfully")
def takeScreen():
msg="TAKEPIC"
s.sendall(bytes(msg,"utf8"))
file = open('server_image.jpg', "wb")
image_chunk = s.recv(2048)
while image_chunk:
if not image_chunk:
break
file.write(image_chunk)
image_chunk = s.recv(2048)
file.close()
return
def Thoat():
msg="QUIT"
s.sendall(bytes(msg,"utf8"))
s.close()
root.destroy()
def thread1():
t1=threading.Thread(target=takeScreen)
t1.start()
def thread2():
t2=threading.Thread(target=ProcessRunning)
t2.start()
root = tk.Tk()
canvas1 = tk.Canvas(root, width=300, height=300)
canvas1.pack()
entry=tk.Entry()
myButton_connect=tk.Button(text="Connect",command=ConnectToServer)
myButton_TakePic = tk.Button(text="Take screenshot", command=thread1, font=10)
myButton_Process = tk.Button(text="Process Running", command=thread2, font=10)
myButton_Exit=tk.Button(text="Thoat",command=Thoat,font=10)
canvas1.create_window(150,50,window=entry)
canvas1.create_window(150, 100, window=myButton_TakePic)
canvas1.create_window(150, 150, window=myButton_Process)
canvas1.create_window(250,50,window=myButton_connect)
canvas1.create_window(150,200,window=myButton_Exit)
root.mainloop()
Server code:
def pic():
myScreenshot=pyautogui.screenshot()
save_path=asksaveasfilename()
myScreenshot.save(save_path+"_capture1.png")
return save_path+"_capture1.png"
HOST=''
PORT=65432
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen()
while True:
conn,addr=s.accept()
while True:
data=conn.recv(1024).decode("utf8")
if data=="TAKEPIC":
path=pic()
im=Image.open(path)
im.show()
file=open(path,'rb')
img_data=file.read(2048)
while img_data:
conn.send(img_data)
img_data=file.read(2048)
file.close()
elif data=="app running":
Process(conn)
elif data=="QUIT":
break;
break;
s.close()
img_gui_tkinter:
After I clicked the "Take screenshot" button, the server program still took pictures and saved them, then it sent to the client successfully (because I was able to open the image).
But the problem is that it pops up a dialog like this:
img_after click take screenshot:
and make my program hang. When I press the close button on the child dialog box, it appears
img_hanging error:
If you choose Close the program, the program on the server side will end.
I found that the client side has an error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\KHAI\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "d:\MangMaYTinh\TuHoc_DoAn\CreateBox_control\Box_Control.py", line 29, in takeScreen
image_chunk = s.recv(2048)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\KHAI\AppData\Local\Programs\Python\Python39\lib\threading.py", line 954, in _bootstrap_inner
self.run()
File "C:\Users\KHAI\AppData\Local\Programs\Python\Python39\lib\threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "d:\MangMaYTinh\TuHoc_DoAn\CreateBox_control\Box_Control_Ver3.py", line 31, in takeScreen
image_chunk = s.recv(2048)
ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine
I've tried to the best of my ability but still can't resolve that error. Hope everyone can help me. I'm just getting started with Python
I see two problems.
Main problem is that socket is low-level object and it doesn't know if it received all file data so it runs next recv(2048) which waits for more data - and this blocks socket and all code.
Code if not image_chunk: break works only when you close socket after sending data but you need socket to send other commands so you can't close it after sending file. You have to send file size before data and then client will know how many data to receive.
you can use struct to convert integer to 4 bytes - so client will have to receive 4 bytes to get size (and convert to integer using struct). Using string with number you don't know how long will be this string and client will not know how many bytes to receive.
Other problem is that sending file may need longer time and socket blocks mainloop which get key/mouse events from system, send events to widgets, update/redraw window/widgets - so GUI freezes.
I skiped this problem. It would need longer and more complex code with thread.
My version with other changes.
server.py
import socket
#from tkinter.filedialog import asksaveasfilename
#from PIL import Image
import pyautogui
#import threading
import struct
import os
import datetime
# --- functions ---
def take_screenshot(): # PEP8: verb as function name
screenshot = pyautogui.screenshot() # PEP8: `lower_case_names` for variables
# PEP8: spaces around `=`
# using `asksaveasfilename()` (or any other GUI elements) on server is useless - user can't see GUI from server
#path = asksaveasfilename()
#path = path + "_capture1.png"
path = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S-%f_capture.png')
screenshot.save(path)
return path
def handle_client(conn, addr):
while True:
print('[handle_client] read command')
command = conn.recv(1024).decode("utf8")
command = command.lower()
print('[handle_client] run command:', command)
if command == "takepic":
print('[handle_client] take screenshot')
path = take_screenshot()
# displaying on serer make no sense because user can't see it.
#im = Image.open(path)
#im.show()
file_size = os.stat(path).st_size
print('[handle_client] file size:', file_size)
file_size = struct.pack('>I', file_size) # convert `integer` to `4 bytes`
conn.send(file_size)
print('[handle_client] open file')
file_handler = open(path,'rb')
total_size = 0
while True:
print('[handle_client] read data chunk from file')
data_chunk = file_handler.read(2048)
size = len(data_chunk)
if not data_chunk:
break
total_size += size
print('[handle_client] send data chunk:', size, 'total:', total_size)
conn.send(data_chunk)
print('[handle_client] close file')
file_handler.close()
elif command == "app running":
Process(conn)
elif command == "quit":
conn.close()
break
# --- main ---
HOST = '' # PEP8: spaces around `=`
PORT = 65432 # PEP8: spaces around `=`
print('Starting ...')
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # PEP8: space after `,`
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # solution for "[Error 89] Address already in use". Use before bind()
s.bind((HOST, PORT))
s.listen()
#all_threads = []
all_clients = []
try:
while True:
print('Waiting for client')
conn, addr = s.accept()
print('Handle client')
# run in current thread - only one client can connect
handle_client(conn, addr)
all_clients.append( (conn, addr) )
# run in separated thread - many clients can connect
#t = threading.Thread(taget=handle_client, args=(conn, addr))
#t.start()
#all_threads.append(t)
except KeyboardInterrupt:
print('Stopped by Ctrl+C')
finally:
s.close()
#for t in all_threads:
# t.join()
for conn, addr in all_clients:
conn.close()
client.py
import socket
import tkinter as tk
import tkinter.messagebox
from PIL import Image
import threading
import struct
# --- functions ---
def connect_to_server(): # PEP8: `lower_case_names` for functions
HOST = entry.get() # PEP8: spaces around `=`
PORT = 65432
try:
s.connect((HOST, PORT)) # PEP8: `
tkinter.messagebox.showinfo(title="Noti", message="Connect Successfully")
except Exception as e:
tkinter.messagebox.showerror(title="Error", message="Error: " + str(e))
def take_screen():
msg = "TAKEPIC"
print('[take_screen] send command:', msg)
s.sendall(msg.encode())
file_size = s.recv(4)
file_size = struct.unpack('>I', file_size)[0] # convert `4 bytes` to `integer`
print('[take_screen] file size:', file_size)
print('[take_screen] open file')
file_handler = open('server_image.jpg', "wb")
total_size = 0
while total_size < file_size:
print('[take_screen] recv data chunk')
data_chunk = s.recv(2048)
size = len(data_chunk)
total_size += size
print('[handle_client] write data chunk:', size, 'total:', total_size)
file_handler.write(data_chunk)
print('[take_screen] close file')
file_handler.close()
tkinter.messagebox.showinfo(title="Success", message="Downloaded Successfully")
def on_exit():
msg = "QUIT"
print('[on_exit] send command:', msg)
s.sendall(msg.encode())
s.close()
root.destroy()
# --- main ---
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=300)
canvas.pack()
entry = tk.Entry()
button_connect = tk.Button(text="Connect", command=connect_to_server)
button_take_pic = tk.Button(text="Take screenshot", command=take_screen)
#button_process = tk.Button(text="Process Running", command=processrunning)
button_exit = tk.Button(text="Exit", command=on_exit)
canvas.create_window(150, 50, window=entry)
canvas.create_window(150, 100, window=button_take_pic)
#canvas.create_window(150, 150, window=button_process)
canvas.create_window(250, 50 , window=button_connect)
canvas.create_window(150, 200, window=button_exit)
root.mainloop()
PEP 8 -- Style Guide for Pyhon Code
Related
I have a basic program where in a Tkinter window a user presses a button that generates a string in a listbox. Using a second send button, I want to transfer those strings through a socket server to a second client. The message printed to the console at the point of departure (client1) is a tuple, and it can be iterated through with a for loop to make it more legible i.e. each element is printed to a new line. Using a print function at the point of arrival (client2), the same tuple is produced, but trying to use a for loop on it iterates through each character in the group of strings, as opposed to each element of the tuple as desired.
This is client1:
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
from tkinter import messagebox
from tkinter import scrolledtext
from tkinter import ttk
from tkinter import font
import os
import datetime
import pickle
def receive():
while True:
try:
msg = client_socket.recv(BUFSIZ).decode("utf8")
except OSError: # Possibly client has left the chat.
break
def send(event=None): # event is passed by binders.
global sent
global current_datetime
global order_list
sent = order_list.get(0, END)
msg = sent
for i in msg:
print(i)
client_socket.send(bytes(str(msg), "utf8"))
if msg == "{quit}":
client_socket.close()
window.quit()
order_list.delete(0, END)
window = tkinter.Tk()
window.title("Title")
window.geometry("1280x1080")
var = IntVar()
var.set(1)
check_Table_Button = False
font = font.Font(family="Arial", size=9, weight="bold")
height = 4
width = 7
padx = 8
pady = 1
order_list=Listbox(window, width=35, height = 35)
order_list.config(font=font)
order_list.grid(row =0, column = 11, columnspan=3, rowspan=8)
def clickedTable(table):
# print(table)
order_list.insert(END, table)
global check_Table_Button
check_Table_Button = True
def addTable(table, number, x) #Sample Button to generate string
table = table
btn_masa_x = Button(window, text=str(table),font=font,
bg="orange", fg="black",
command=lambda: clickedTable(table),
height=height, width=width,
padx=padx+1, pady=pady)
btn_masa_x.grid(column=x, row=number, rowspan=1, columnspan=1)
addTable("Table 1 ", 0, 0)
def send_button():#Second button to send over socket
send_button =Button(window, text="Send",
font=font, bg="lime green",
command=lambda: send(),
height=height, width=width,
padx=padx, pady=pady)
send_button.grid(column=10, row = 8, rowspan=1)
send_button()
HOST = "127.0.0.1"
PORT = 33000
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
window.mainloop()
This is the server:
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
def accept_incoming_connections():
"""Sets up handling for incoming clients."""
while True:
client, client_address = SERVER.accept()
print("%s:%s has connected." % client_address)
# client.send(bytes("Greetings from the cave! Now type your name and press enter!", "utf8"))
addresses[client] = client_address
Thread(target=handle_client, args=(client,)).start()
def handle_client(client): # Takes client socket as argument.
"""Handles a single client connection."""
name = client.recv(BUFSIZ).decode("utf8")
# welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % name
# client.send(bytes(welcome, "utf8"))
msg = "%s has joined the chat!" % name
# broadcast(bytes(msg, "utf8"))
clients[client] = name
while True:
msg = client.recv(BUFSIZ)
if msg != bytes("{quit}", "utf8"):
broadcast(msg)
# broadcast(msg, name + ": ")
else:
client.send(bytes("{quit}", "utf8"))
client.close()
del clients[client]
broadcast(bytes("%s has left the chat." % name, "utf8"))
break
def broadcast(msg, prefix=""): # prefix is for name identification.
"""Broadcasts a message to all the clients."""
for sock in clients:
sock.send(bytes(prefix, "utf8") + msg)
clients = {}
addresses = {}
HOST = '127.0.0.1'
PORT = 33000
BUFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)
if __name__ == "__main__":
SERVER.listen(5)
print("Waiting for connection...")
ACCEPT_THREAD = Thread(target=accept_incoming_connections)
ACCEPT_THREAD.start()
ACCEPT_THREAD.join()
SERVER.close()
And this is client2:
from threading import Thread
import tkinter
import pickle
def receive():
"""Handles receiving of messages."""
while True:
try:
msg =client_socket.recv(BUFSIZ)#.decode("utf-8")
msg = pickle.loads(msg)
print(msg)
# msg_list.insert(tkinter.END,msg)
except OSError: # Possibly client has left the chat.
break
def send(event=None): # event is passed by binders.
"""Handles sending of messages."""
msg = my_msg.get()
my_msg.set("") # Clears input field.
client_socket.send(bytes(msg, "utf8"))
if msg == "{quit}":
client_socket.close()
top.quit()
def on_closing(event=None):
"""This function is to be called when the window is closed."""
my_msg.set("{quit}")
send()
top = tkinter.Tk()
top.title("Chatter")
messages_frame = tkinter.Frame(top)
my_msg = tkinter.StringVar() # For the messages to be sent.
scrollbar = tkinter.Scrollbar(messages_frame) # To navigate through past messages.
# Following will contain the messages.
msg_list = tkinter.Listbox(top,width=40,height=10)
msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
messages_frame.pack()
entry_field = tkinter.Entry(top, textvariable=my_msg)
entry_field.bind("<Return>", send)
entry_field.pack()
send_button = tkinter.Button(top, text="Send", command=send)
send_button.pack()
top.protocol("WM_DELETE_WINDOW", on_closing)
#----Now comes the sockets part----
# HOST = input('Enter host: ')
HOST = "127.0.0.1"
# PORT = input('Enter port: ')
PORT = 33000
if not PORT:
PORT = 33000
else:
PORT = int(PORT)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
tkinter.mainloop()
As I said above, the msg variable in client2, the one that receives the message, is printed as a tuple but a for loop will iterate over each character of the strings contained.
Using the pickle module I received two separate errors.
When I pass .decode("utf-8) and then .loads() it says "Could not find MARK).
Without the .decode(), the error is "unpickling stack underflow".
My desired outcome is for each of the individual strings that arrive over the TCP socket to be added to the listbox in client2 on a new line, and without the ('', '') symbols.
Should I try to convert it to a .json object?
Or will another networking module produce better results?
I'm sorry about the length of code and the potentially obvious answer. Beginner to networking.
I am trying to make a simple chat application using Python 3. I have seen this work in the past, where my client is able to connect to my server, and messages can be sent successfully. I want to move the app from a script working in the python idle shell to a GUI built with TKinter. Using entry and button widgets, a client can connect to the server for a fraction of a second, then is immediately disconnected. This only seems to happen because I am trying to use tkinter.
Error message is:
%$%$ has connected.
Exception in thread Thread-33:
Traceback (most recent call last):
File "C:\Users\lmaor\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "C:\Users\lmaor\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\lmaor\Desktop\Server 2.py", line 32, in handle_client
name = client.recv(BUFSIZ).decode("utf8")
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
The client-side code is:
#Importing packages
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
import tkinter
from tkinter import *
from tkinter import messagebox
global client_socket
global HOST
global PORT
#These are here to stop the program breaking later on
HOST = 1
PORT = 1
BUFSIZ = 1024
client_socket = socket(AF_INET, SOCK_STREAM)
#This unsuccessfully connects to the server
def connect():
HOST = etyHost.get()
PORT = etyPort.get()
if not PORT:
PORT = 33000 # Default value.
else:
PORT = int(PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
#Creates a function to receive messages at any time
def receive():
while True:
try:
global client_socket
msg = client_socket.recv(BUFSIZ).decode("utf8")
msgChatlog.insert(END, msg)
except OSError:
break
#Creates a function to send messages
def send(event=None): #Event is passed by binders
msg = varMessage.get()
varMessage.set("") #Clears input field
client_socket.send(bytes(msg, "utf8"))
if msg == "{quit}":
client_socket.close()
top.quit()
#When closing window
def on_closing(event=None):
varMessage.set("{quit}")
send()
#Create tkinter window
jahchat = Tk()
jahchat.geometry("500x500")
jahchat.configure(background = "black")
jahchat.resizable(False, False)
jahchat.title("JahChat")
#
#Frame contains everything. useless
frmMessage = Frame()
#Var message is what goes into the chat
varMessage = StringVar() # For the messages to be sent.
varMessage.set("Type your messages here.")
#Scrollbar for the chatlog
srlChatlog = Scrollbar(frmMessage) # To navigate through past messages.
#
msgChatlog = Listbox(frmMessage, height=15, width=100, yscrollcommand=srlChatlog.set)
srlChatlog.pack(side=RIGHT, fill=Y)
msgChatlog.pack(side=LEFT, fill=BOTH)
msgChatlog.pack()
frmMessage.pack()
#
etyMessage= Entry(textvariable=varMessage)
etyMessage.bind("<Return>", send)
etyMessage.pack()
btnMessage = Button(text="Send", command=send)
btnMessage.pack()
#jahchat.protocol("WM_DELETE_WINDOW", on_closing)
#Entry box
etyHost = Entry(jahchat)
etyHost.pack()
etyHost.place(x = 0, y = 250)
#Entry box
etyPort = Entry(jahchat)
etyPort.pack()
etyPort.place(x = 0, y = 275)
#Button
btnConnect = Button(jahchat, text = "Connect", command = connect)
btnConnect.config(width = 20)
btnConnect.place(x = 0, y = 320)
#========================================================
#This is the code that sucessfully connects to the server
#HOST = input("host")
#PORT = input("port")
#if not PORT:
# PORT = 33000 # Default value.
#else:
# PORT = int(PORT)
#client_socket = socket(AF_INET, SOCK_STREAM)
#BUFSIZ = 1024
#ADDR = (HOST, PORT)
#print (ADDR)
#print (type(ADDR))
#client_socket.connect(ADDR)
#receive_thread = Thread(target=receive)
#receive_thread.start()
#===========================================================
jahchat.mainloop() # Starts GUI execution.
The server code is:
#Importing packages
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
#Sets up constant variables for later use
clients = {}
addresses = {}
HOST = '' #Client has to set this as their host to connect
PORT = 33000 #Client has to set this as their port to connect
BUFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)
#Creates a function that handles clients into the server
def accept_incoming_connections():
while True:
client, client_address = SERVER.accept()
print ("%$%$ has connected." .format(client_address))
client.send(bytes("Greetings from the cave!" + "Now type your name and press enter!", "utf8"))
addresses[client] = client_address
Thread(target=handle_client, args=(client,)).start()
#Takes client socket as argument.
def handle_client(client):
name = client.recv(BUFSIZ).decode("utf8")
welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % name
client.send(bytes(welcome, "utf8"))
msg = "%s has joined the chat!" % name
broadcast(bytes(msg, "utf8"))
clients[client] = name
while True:
msg = client.recv(BUFSIZ)
if msg != bytes("{quit}", "utf8"):
broadcast(msg, name+": ")
else:
client.send(bytes("{quit}", "utf8"))
client.close()
del clients[client]
broadcast(bytes("%s has left the chat." % name, "utf8"))
break
#Broadcasts message to whole server
def broadcast(msg, prefix=""): #Prefix is for name identification.
for sock in clients:
sock.send(bytes(prefix, "utf8")+msg)
def checkIP():
print (HOST, PORT, ADDR)
if __name__ == "__main__":
SERVER.listen(5) # Listens for 5 connections at max.
print("Waiting for connection...")
ACCEPT_THREAD = Thread(target=accept_incoming_connections)
ACCEPT_THREAD.start() #Starts the infinite loop.
ACCEPT_THREAD.join()
SERVER.close()
All answers appreciated.
I have a tcp receiver which is listening for incoming images. I also have a foo() def that runs simultaneously and prints the current time every 5 seconds.
Here is the code:
from __future__ import print_function
import socket
from struct import unpack
import Queue
from PIL import Image
HOST = '10.0.0.1'
PORT = 5005
BUFSIZE = 4096
q = Queue.Queue()
class Receiver:
''' Buffer binary data from socket conn '''
def __init__(self, conn):
self.conn = conn
self.buff = bytearray()
def get(self, size):
''' Get size bytes from the buffer, reading
from conn when necessary
'''
while len(self.buff) < size:
data = self.conn.recv(BUFSIZE)
if not data:
break
self.buff.extend(data)
# Extract the desired bytes
result = self.buff[:size]
# and remove them from the buffer
del self.buff[:size]
return bytes(result)
def save(self, fname):
''' Save the remaining bytes to file fname '''
with open(fname, 'wb') as f:
if self.buff:
f.write(bytes(self.buff))
while True:
data = self.conn.recv(BUFSIZE)
if not data:
break
f.write(data)
import time, threading
def foo():
try:
print(time.ctime())
threading.Timer(5, foo).start()
except KeyboardInterrupt:
print('\nClosing')
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sock.bind((HOST, PORT))
except socket.error as err:
print('Bind failed', err)
return
sock.listen(1)
print('Socket now listening at', HOST, PORT)
try:
while True:
conn, addr = sock.accept()
print('Connected with', *addr)
# Create a buffer for this connection
receiver = Receiver(conn)
# Get the length of the file name
name_size = unpack('B', receiver.get(1))[0]
# Get the file name itself
name = receiver.get(name_size).decode()
q.put(name)
print('name', name)
# Save the file
receiver.save(name)
conn.close()
print('saved\n')
# Hit Break / Ctrl-C to exit
except KeyboardInterrupt:
print('\nClosing')
sock.close()
if __name__ == '__main__':
foo()
main()
The problem is that when I press Ctrl + C buttons in order to terminate the program, the first time it prints "closing" but it isn't terminated and I should press these buttons at least two times.
How can I stop the program the first time I press Ctrl + C? I removed try and except in def foo(), but it didn't change the result.
Just reraise the exception after the print statement:
except KeyboardInterrupt:
print('\nClosing')
raise
I'm trying to write a simple messenger app with Python and Tkinter. I'm listening to to a UDPSock to receive input. However as Tkinter's mainloop() blocks the thread, I cannot receive input with only one thread. I've tried to send a reference to the Tkinter GUI to the Process that loops and listens to input but I get a Can't pickle 'tkapp' object error. As the input is continuous and the Tkinter thread can't do anything else except run the mainloop to handle the GUI I cannot put the received input onto the GUI. Even if I use a Pipe the Tkinter thread is running the mainloop and so there is nowhere I can put a
while True:
data = pipe_conn.recv()
# do something with data
or anything.
Any help would be much appreciated!
My code:
-- imports --
class MessageApp():
def __init__(self, root, host, conn, port=13000):
# Setup GUI
self.send_sock = socket(AF_INET, SOCK_DGRAM)
p = Process(target=self.recv, args=(conn,))
def recv(self, conn):
buff = 1024
print('recvin')
while True:
(data, addr) = conn.recvfrom(buff)
self.add_msg(addr + ": " + data)
def start(self):
self.root.mainloop()
def add_msg(self, text):
self.msgs.config(state=NORMAL)
self.msgs.insert(INSERT, text + "\n")
self.msgs.config(state=DISABLED)
def send(self):
self.add_msg(self.inpt.get())
self.send_sock.sendto(self.inpt.get(), self.send_addr)
self.inpt.delete(0, 'end')
# ----------WHERE CAN I PUT THIS------------
def msg_listen(messenger, conn, port=13000):
buff = 1024
recv_sock = socket(AF_INET, SOCK_DGRAM)
recv_sock.bind(('', port))
while True:
(data, addr) = recv_sock.recvfrom(buff)
conn.send()
recv_sock.close()
# ------------------------------------------
def msgr_init(conn):
root = Tk()
messenger = MessageApp(root, ip, conn)
messenger.start()
if __name__ == "__main__":
root = Tk(
par_conn, chd_conn = Pipe(True)
msg_proc = Process(target=msgr_init, args=(chd_conn,))
msg_proc.start()
msg_listen(messenger, par_conn)
I discovered Tkinter.after() after reading the docs and it solved my problem.
I'm testing a client/server clipboard sharing program (because RDP doesn't for reasons i couldn't find). It works fine, but when i activate the client's clipboard writing code, the server thread crashes about 20 seconds after a copy:
_tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined
What am i doing wrong? Here's my code, which i ran in two command windows using python share_clipboard.py S and python share_clipboard.py C localhost:
"""
Share clipboard
by Cees Timmerman
01-12-2014 v0.1
"""
import socket, sys, threading
from time import sleep
try: from tkinter import Tk # Python 3
except: from Tkinter import Tk
def dec(s):
return s.decode('utf-8')
def enc(s):
return s.encode('utf-8')
# http://stackoverflow.com/questions/17453212/multi-threaded-tcp-server-in-python
class ClientThread(threading.Thread):
def __init__(my, sock):
threading.Thread.__init__(my)
my.sock = sock
def run(my):
print("Connection from : %s:%s" % (ip, str(port)))
#my.sock.send(enc("\nWelcome to the server\n\n"))
'''
data = "dummydata"
while len(data):
data = dec(clientsock.recv(2048))
print("Client sent : "+data)
my.sock.send(enc("You sent me : "+data))
'''
old_clip = None
while True:
new_clip = tk.clipboard_get()
if new_clip != old_clip:
print("New clip: %r" % new_clip)
old_clip = new_clip
my.sock.sendall(enc(new_clip))
sleep(1)
print("Client disconnected...")
if 1 < len(sys.argv) < 4:
cs = sys.argv[1]
ip = sys.argv[2] if len(sys.argv) == 3 else "0.0.0.0"
else:
print("Usage: %s <C|S> [IP]")
sys.exit()
tk = Tk()
port = 9999
if cs == "S":
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind((ip, port))
threads = []
# Listen for connections.
while True:
tcpsock.listen(4)
print("\nListening for incoming connections...")
(clientsock, (ip, port)) = tcpsock.accept()
newthread = ClientThread(clientsock)
newthread.start()
threads.append(newthread)
# Wait for threads to finish.
for t in threads:
t.join()
else:
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect((ip, port))
while True:
data = clientsocket.recv(1024)
print(data)
#tk.withdraw()
#tk.clipboard_clear()
#tk.clipboard_append(data) # Causes error on server: _tkinter.TclError: CLIPBOARD selection doesn't exist or form "STRING" not defined
#tk.destroy()