title: Tkinter - Multithreading / Multiprocessing - Which one fits better in this code?
body: <p>I'm kind of a newbie here so excuse me if I don't get my point as clear as it should be. </p>
  
  <p>I'm trying to improve a server I wrote some months ago in sockets with Tkinter. I used a template I found on the internet. Everything seems to work smooth and fine until I get to the server.listening() part. At that point Tkinter will always freeze. I know it has something to do with multithreading, multiprocessing and the fact of putting that thread outside the main loop, but I can't seem to find any solution so far. </p>
  
  <p>The server actually works, even though Tkinter freezes everytime I hit the button for "listening". So, here's my point. It doesn't really matter if it completely freezes Tkinter for a couple of seconds, since this server won't be able to do much until there's at least one person connected to it. I only want the program to be able to activate "listening" when the proper button is pressed, and deactivate it when I need it. </p>
  
  <p>Would you kindly throw some light upon my doubt? I've been like 2 days constantly fighting against this and only managed to get this far. I will leave the full code at the end of this post, just in case you consider necessary to run it first. So here's the code, with some parts removed for the sake of simplicity: </p>
  
  <pre><code>from socket import AF_INET, socket, SOCK_STREAM
  from threading import Thread
  from datetime import date
  from tkinter import messagebox
  from tkinter import *
  from tkinter import ttk, font
  from multiprocessing import Process
  
  
  import getpass
  import os
  import time
  
  global msgs
  global opt
  global ADDR
  global MK1
  
  
  
  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)
  
  
  class threads():
  
  
  
      def accept_incoming_connections():
          """Sets up handling for incoming clients."""
  
          while True:
              global client_address
              client, client_address = SERVER.accept()
              client.send(bytes("Introduce un nombre y pulsa enter ", "utf8"))
  
              client.send(bytes("Asegurate de borrar 'Escribe...' antes de enviar tu nombre", "utf8"))
              addresses[client] = client_address
              Thread(target=threads.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 = 'Bienvenido %s! Pulsa el botón "Salir" para salir. No pulses X.' % name
          client.send(bytes(welcome, "utf8"))
          msg = "%s se ha unido al 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 se ha ido del chat." % name, "utf8"))
                  break
  
  
  
  
  class IP():
  
      def __init__(self):
          # Tkinter part for defining the IP of the server. This works smoothly.
  
          global ip1
          ip1 = 1
  
      def aceptar(self):
          global HOST
          global PORT
          HOST = self.dip.get() 
          PORT = self.port.get()
          if not PORT:
              PORT = 33000
  
          PORT = int(PORT)
          self.raiz.destroy()
  
          global host1
          host1 = 1
  
  
          global ADDR
          ADDR = (HOST, PORT)
  
          global SERVER
          SERVER = socket(AF_INET, SOCK_STREAM)
          SERVER.bind(ADDR)
  
  
  
      def borrar_mensa(self, evento):
          self.dip.set("")
          self.port.set("")
  
  
  
  class main ():
  
          def __init__(self):
  
  
  
              def send(event=None):  # event is passed by binders.
                  """Handles sending of messages."""
                  msg1 = my_msg.get()
                  my_msg.set("")  # Clears input field.
                  msg_list.insert(tkinter.END, msg1)
                  if msg1 == "{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("Servidor - Aristoi.................. V. 1.0")
              top.geometry("650x450")
  
              messages_frame = tkinter.Frame(top)
              my_msg = tkinter.StringVar()  # For the messages to be sent.
              my_msg.set("Introduzca función...")
              scrollbar = tkinter.Scrollbar(messages_frame)  # To navigate through past messages.
  
              # Following will contain the messages.
              global msg_list
              msg_list = tkinter.Listbox(messages_frame, height=23, width=95, yscrollcommand=scrollbar.set)
  
              #  Following will contain buttons functions.
              def SERVERclose():
                  SERVER.close()
  
              def EXIT():
                  top.destroy()
  
              def def_IP():
                  if ip1 is None:
                      IP()
                  else:
                      tkinter.messagebox.showerror(title="Error", message="IP ya definida. Reinicie")
  
              def listening():
                  if host1 is None:
                      tkinter.messagebox.showerror(title="Error", message="No ha definido una IP para el servidor")
  
                  else:
                      SERVER.listen(5)
                      INPUT = Thread(target=threads.accept_incoming_connections)
                      INPUT.start()
                      tkinter.messagebox.showinfo(title="Conectando", message="Esperando conexiones entrantes")
                      INPUT.join()
                      SERVER.close()
                      global host2
                      host2 = 1                             
  
  
              # BUTTONS
              separl = ttk.Separator(top, orient=HORIZONTAL)
              entry_field = tkinter.Entry(top, textvariable=my_msg, width = 95)
              entry_field.bind("&lt;Return&gt;", send)
              send_button = tkinter.Button(top, text="    Enviar    ", fg="black", command=send)
              salir = tkinter.Button(top, text="    Salir    ",bg="black", fg="white", command=EXIT)
              host = tkinter.Button(top, text="    IP    ",bg="black", fg="white", command=def_IP)
              connect = tkinter.Button(top, text="    Conectar    ",bg="black", fg="white", command=listening)
              servcls = tkinter.Button(top, text="    ServerCLose    ",bg="black", fg="white", command=SERVERclose)
  
              #STETICS
  
              scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
              msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
              messages_frame.pack()
              entry_field.pack()
              send_button.pack()
              entry_field.place(x=29, y=380)
              send_button.place(x=29, y=410)
              salir.place(x=580, y=410)
              host.place(x=480, y = 410)
              connect.place(x=380, y = 410)
              servcls.place(x=280, y = 410)
  
              top.protocol("WM_DELETE_WINDOW", on_closing)
              top.mainloop()
  
  
  
  
  
  clients = {}
  addresses = {}
  
  PORT = 33000
  BUFSIZ = 1024
  
  opt = int(0)
  MK1 = 1
  global host1
  global host2
  global ip1
  
  host1 = None
  host2 = None
  ip1 = None
  
  
  if __name__ == "__main__":
      main()
  </code></pre>
  
  <p>Here's the full version of the code:</p>
  
  <pre><code>from socket import AF_INET, socket, SOCK_STREAM
  from threading import Thread
  from datetime import date
  from tkinter import messagebox
  from tkinter import *
  from tkinter import ttk, font
  from multiprocessing import Process
  
  
  import tkinter
  import getpass
  import os
  import time
  
  global msgs
  global opt
  
  global ADDR
  global MK1
  
  
  
  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)
  
  
  class threads():
  
  
  
      def accept_incoming_connections():
          """Sets up handling for incoming clients."""
  
          while True:
              global client_address
              client, client_address = SERVER.accept()
              client.send(bytes("Introduce un nombre y pulsa enter ", "utf8"))
  
              client.send(bytes("Asegurate de borrar 'Escribe...' antes de enviar tu nombre", "utf8"))
              addresses[client] = client_address
              Thread(target=threads.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 = 'Bienvenido %s! Pulsa el botón "Salir" para salir. No pulses X.' % name
          client.send(bytes(welcome, "utf8"))
          msg = "%s se ha unido al 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 se ha ido del chat." % name, "utf8"))
                  break
  
  
  
  
  class IP():
  
      def __init__(self):
  
          self.raiz = Tk()
          self.raiz.geometry("450x200")
          self.raiz.resizable(0,0)
          self.raiz.title("Ventana de direcciones")
  
          fuente = font.Font(weight="bold")
  
          self.etiq1 = ttk.Label(self.raiz, text="Dirección IP", font=fuente)
          self.etiq2 = ttk.Label(self.raiz, text="Puerto", font=fuente)
  
          self.dip = StringVar()
          self.port = StringVar()
  
          self.ctext1 = ttk.Entry(self.raiz, textvariable=self.dip , width=40)
          self.ctext2 = ttk.Entry(self.raiz, textvariable=self.port, width= 10)
  
          self.separ1 = ttk.Separator(self.raiz, orient=HORIZONTAL)
  
          self.boton1 = ttk.Button(self.raiz, text="Aceptar", command=self.aceptar)
  
          self.etiq1.place(x=30, y=40)
          self.etiq2.place(x=30, y=80)
  
          self.ctext1.place(x=150, y=42)
          self.ctext2.place(x=150, y=82)
          self.separ1.place(x=5, y=145, bordermode=OUTSIDE,height=10, width=420)
  
          self.boton1.place(x=170, y=160)
  
          self.ctext1.focus_set()
  
          self.ctext1.bind("&lt;Button-1&gt;", self.borrar_mensa)
          self.ctext2.bind("&lt;Button-1&gt;", self.borrar_mensa)
          global ip1
          ip1 = 1
  
      def aceptar(self):
          global HOST
          global PORT
          HOST = self.dip.get() 
          PORT = self.port.get()
          if not PORT:
              PORT = 33000
  
          PORT = int(PORT)
          self.raiz.destroy()
  
          global host1
          host1 = 1
  
  
          global ADDR
          ADDR = (HOST, PORT)
  
          global SERVER
          SERVER = socket(AF_INET, SOCK_STREAM)
          SERVER.bind(ADDR)
  
  
  
      def borrar_mensa(self, evento):
          self.dip.set("")
          self.port.set("")
  
  
  
  class main ():
  
          def __init__(self):
  
  
          # accept_incoming_connections ---------------------------------------------------------------
  
  
              def host_log(self):
                  msgs = "%s:%s se ha conectado a las " + current_time + " del día " + today
                  msg_list.insert(tkinter.END, msgs)
  
  
  
          #  --------------------------------------------------------------------------------------------
  
  
  
          #Parte del Tkinter
          #-----------------------------------------
  
  
              def send(event=None):  # event is passed by binders.
                  """Handles sending of messages."""
                  msg1 = my_msg.get()
                  my_msg.set("")  # Clears input field.
                  msg_list.insert(tkinter.END, msg1)
                  if msg1 == "{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("Servidor - Aristoi.................. V. 1.0")
              top.geometry("650x450")
  
              messages_frame = tkinter.Frame(top)
              my_msg = tkinter.StringVar()  # For the messages to be sent.
              my_msg.set("Introduzca función...")
              scrollbar = tkinter.Scrollbar(messages_frame)  # To navigate through past messages.
  
              # Following will contain the messages.
              global msg_list
              msg_list = tkinter.Listbox(messages_frame, height=23, width=95, yscrollcommand=scrollbar.set)
  
              def SERVERclose():
                  SERVER.close()
  
              def EXIT():
                  top.destroy()
  
              def def_IP():
                  if ip1 is None:
                      IP()
                  else:
                      tkinter.messagebox.showerror(title="Error", message="IP ya definida. Reinicie")
  
              def listening():
                  if host1 is None:
                      tkinter.messagebox.showerror(title="Error", message="No ha definido una IP para el servidor")
  
                  else:
                      SERVER.listen(5)
                      INPUT = Thread(target=threads.accept_incoming_connections)
                      INPUT.start()
                      tkinter.messagebox.showinfo(title="Conectando", message="Esperando conexiones entrantes")
                      INPUT.join()
                      SERVER.close()
                      global host2
                      host2 = 1                             
  
  
              # BOTONES
              separl = ttk.Separator(top, orient=HORIZONTAL)
              entry_field = tkinter.Entry(top, textvariable=my_msg, width = 95)
              entry_field.bind("&lt;Return&gt;", send)
              send_button = tkinter.Button(top, text="    Enviar    ", fg="black", command=send)
              salir = tkinter.Button(top, text="    Salir    ",bg="black", fg="white", command=EXIT)
              host = tkinter.Button(top, text="    IP    ",bg="black", fg="white", command=def_IP)
              connect = tkinter.Button(top, text="    Conectar    ",bg="black", fg="white", command=listening)
              servcls = tkinter.Button(top, text="    ServerCLose    ",bg="black", fg="white", command=SERVERclose)
  
              #ESTETICA
  
              scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
              msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
              messages_frame.pack()
              entry_field.pack()
              send_button.pack()
              entry_field.place(x=29, y=380)
              send_button.place(x=29, y=410)
              salir.place(x=580, y=410)
              host.place(x=480, y = 410)
              connect.place(x=380, y = 410)
              servcls.place(x=280, y = 410)
  
              top.protocol("WM_DELETE_WINDOW", on_closing)
              top.mainloop()
  
          # AQUI
  
  
  
  
  clients = {}
  addresses = {}
  
  PORT = 33000
  BUFSIZ = 1024
  
  opt = int(0)
  MK1 = 1
  global host1
  global host2
  global ip1
  
  host1 = None
  host2 = None
  ip1 = None
  
  
  
  
  
  t = time.localtime()
  current_time = time.strftime("%H:%M:%S", t)
  d1 = date.today()
  today = d1.strftime("%d/%m/%Y")
  
  
  
  
  if __name__ == "__main__":
      main()
  </code></pre>