Hi there,

I've had a good, but frustrating, weekend trying to do a bit of client / server socket communication betweem my phone and my pc.

I am trying to write an app (similar to something described in the PyS60 documentation) that has a UI in the main thread and a socket listening in another thread. When the listening thread receives information it should notify the UI via a callback. I have studied both the rssreader.py example and the applicationskeleton example.py to lead where I am going

The problem i have is that once the connection has been made (and despite launching a new thread for this purpose) the UI no longer responds (to either softkeys) and I can't exit the application. I end up having to restart my phone to regain control (I can't run under an emulator as the connection is over bluetooth and I am connecting to a machine not supported by Nokias emulators :-(.

I have done a number of google searches and whilst the PythonGotchas page (on the post neo wiki) has a topic called Series60Threading, the resultant page has been spammed and there is no useful information.

Can someone take a look below and let me know what I am doing wrong. In my head I am either getting my socket programming mixed up or I have forgotten how to do threading as I have been using J2EE containers for too long!

Thanks in advance and thanks for producing something that has let me lose my weekend :-)

Code:
import e32
import appuifw, socket

commands = {1:'hello'}

class UnSunkClientListener:
	def __init__(self, target):
		self.lock=e32.Ao_lock()
		self.callbacks=[]
		self.target = target
		self.soc = socket.socket(socket.AF_BT, socket.SOCK_STREAM)
		
	def registerCallback(self, callback):
		self.callbacks.append(callback)
		
	def _notifyCallbacks(self, *args):
		for x in self.callbacks:
			x(*args)
		
	def _process(self):
		while 1:
			op = self.soc.recv(1)
			print op
		
	def connect(self):
		self.soc.connect(self.target)
		import thread
		if e32.is_ui_thread() == True:
			self.t = thread.start_new_thread(self._process, ())

	def disconnect(self):
		self.t.exit()
		self.soc.disconnect()

class UnSunkClientUI:
	def __init__(self):
		self.lock = e32.Ao_lock()
		self.exitFlag=False
		self.oldExitKeyHandler=appuifw.app.exit_key_handler
		self.oldAppBody=appuifw.app.body
		self.oldTitle=appuifw.app.title
		appuifw.app.title=u'UnSunk Client'
		appuifw.app.exit_key_handler = self.abort
		appuifw.app.menu=[(u"Connect...", self.connect)]
		
	def run(self):
		try:
			self.lock.wait()
			while not self.exitFlag:
				self.refresh()
				self.lock.wait()
		finally:
			self.close()
			
	def close(self):
		appuifw.app.menu = []
		appuifw.app.body = self.oldAppBody
		appuifw.app.exit_key_handler = self.oldExitKeyHandler
		appuifw.app.title = self.oldTitle

	def notify(self, context):
		#invoked when action happens from the listener
		self.lock.signal()
		pass
		
	def refresh(self):
		#update UI following an update
		pass
		
	def connect(self):
		address,services=socket.bt_discover()
		if len(services)>1:
			choices=services.keys()
			choices.sort()
			choice=appuifw.popup_menu([unicode(services[x])+": "+x for x in choices],u'Choose port:')
			target=(address,services[choices[choice]])
		else:
			target=(address,services.values()[0])
		self.listener = UnSunkClientListener(target)
		self.listener.registerCallback(self.notify)
		self.listener.connect()
		appuifw.app.menu=[(u"Disconnect", self.disconnect),(u"Exit", self.abort)]
		
	def disconnect(self):
		self.listener.disconnect()
		appuifw.app.menu=[(u"Connect...", self.connect)]
		
	def abort(self):
		# Exit-key handler.
		self.exitFlag = True
		self.lock.signal()
		

def main():
    client = UnSunkClientUI()
    client.run()

if __name__ == "__main__":
    main()