Tkinter & socket question

Matthew Cincera r14382 at email.sps.mot.com
Fri Jun 25 17:19:58 EDT 1999


Hello,

I have had a lot of experience with socket/Tkinter over the years
and have one simple recommendation.  If you are going to use a
lot of event based updates of UI's based on socket interactions,
use the tcl sockets instantiated in a tcl interpreter inside
of your GUI program.  The createfilehandler is not supported
on Windows any longer (starting with tcl/tk 8.0).  Using after()
and polling are alternatives, but using the native tcl sockets
will put everything in the tcl/tk event loop (this is my humble
opinion, so take it for what it is worth).  I have used native
python sockets but the limitation is really on the tcl/tk side,
not the python side.  Another bonus is tcl handles more of
the socket housecleaning stuff.

Here's some code snips to do some simple socket serving inside
of Python using the tcl sockets layer.  This example is not fully
functional but hopefully this gives you ideas.  It is based on
prior postings in this newsgroup.

Regards,

Matt
--------------------------------------------------------------
import Tkinter

class _Callback:
 """ A foundation class used for representing callbacks.
  Methods added by this class:

  __call__()  - Apply function for the callback

 """

     # =========================================================================

 def __init__(self, callback):
  self.callback = callback
  self.name     = "cb%d" % id(self)

     # =========================================================================

 def __call__(self, *args):
  return apply(self.callback, args)

class Server:

  def __init__(self):

    self.acceptCb = _Callback(self.acceptRequest)
    self.connection.tk.createcommand(self.acceptCb.name, self.acceptCb)
    self.handleCb = _Callback(self.handleRequest)
    self.connection.tk.createcommand(self.handleCb.name, self.handleCb)

    self.connection = Tkinter.Tk()
    self.connection.withdraw()


  #=================================================================================
  def acceptRequest(self, sock, addr, port):
    # Accept the connection request
    self.connection.tk.eval('fconfigure ' + sock + ' -buffering none')
    self.connection.tk.eval('fconfigure ' + sock + ' -translation binary')
    self.connection.tk.eval('fileevent ' + sock + ' readable [list ' + self.handleCb.name + ' '
+ sock + ' ' + addr + ' ' + port + ']')

  #=================================================================================
  def handleRequest(self, sock, addr, port):
    try:
      self.processMessage( sock, addr )
    except _ClientShutdown:
      self.handleClientShutdown( sock, addr )
    except:
      print 'error'

....
  def serveForever(self):
    self.connection.tk.mainloop()


------------------------------------------------------------------------------------

Michael P. Reilly wrote:

> Gregory A. Landrum <landrum at foreman.ac.rwth-aachen.de> wrote:
>
> :>2) I need to poll the connection periodically, say, every second. This would
> :>not have been a problem in console mode... I don't know how to do this in a
> :>Tkinter environment though. So, how can I do something every second (or every
> :>n milliseconds, or whatever the time span may be)? Are threads the way to go?
> :>I haven't used them before.
>
> : Wow, a question I can answer.... amazing.
> : Obligatory-Mandatory-Necessary-Essential Disclaimer:  I bear no
> : resemblance whatsoever to a python wizard, I just happen to have done
> : something like what you want to do.  There's almost definitely a
> : better way of doing this, but my method seems to work.
>
> : I assume that you have already opened a nonblocking socket connection,
> : and that that is what you are polling.  Your main Tkinter window has a
> : method called "after" which can be used to do the polling.
> : Documentation can be found at:
> : http://www.pythonware.com/library/tkinter/introduction/x8550-alarm-handlers-and-other.htm
>
> : An example, in my stupid little networked python game, I have the
> : following polling function:
> :     def ListenForMessages(self):
> :         msg = None
> :         theConn = None
> :
> :  # Check to see if we are the client or the server
> :         if self.serverActive == 1:
> :             if self.clientConn is None:
> :                 print "No Client!"
> :                 return
> :             theConn = self.clientConn
> :         elif self.clientActive == 1:
> :             theConn = self.socket
>
> :         if theConn is None: return
>
> :  # see if there is anything there to read
> :         try:
> :             msg = theConn.recv(1024)
> :      # Got it!  Dispatch the message.
> :             self.Dispatch(self.message.Type(msg),msg)
> :         except error:
> :      # nope... no one loves us.
> :             pass
>
> :  # re-register the after callback, with a 200msec delay
> :         self.listenID = self.Game.rootWin.after(200,self.ListenForMessages)
>
> : The last line is important, because the after callback is removed
> : after being called.  So it needs to be re-registered with Tk.
>
> : The callback is first registered immediately upon establishing the
> : socket connection.
>
> You can also deal directly with Tcl/Tk's filehandler:
>
>   from Tkinter import tkinter
>   self.root.tk.createfilehandler(socket, tkinter.READABLE,
>     self.handle_msg
>   )
>   ...
>   self.root.tk.deletefilehandler(socket)
>
> The mainloop() method handles the rest for you.
>
>   -Arcege





More information about the Python-list mailing list