Thread WebSocketServer



  • Dear pythonist,
    Have trouble for writing threaded WebSocketEchoServer :
    Code working without thread.
    Code working with thread but hang somme times with
    "ERROR A stack overflow in task Thread has been detected. "

    If anyone knows more me about thread and how to debug

    Thanks for any help
    cheers !!
    Here my file "wsServer.py" :

    
    from hashlib import sha1
    
    from ubinascii import b2a_base64 as b64encode
    import sys
     
    from time import sleep_ms
    import micropython
    import socket
    import struct
    import ujson
    from struct import unpack,calcsize
    from network import Server
    from _thread import *
    micropython.alloc_emergency_exception_buf(100)
    
    FIN    = 0x80
    OPCODE = 0x0f
    MASKED = 0x80
    PAYLOAD_LEN = 0x7f
    PAYLOAD_LEN_EXT16 = 0x7e
    PAYLOAD_LEN_EXT64 = 0x7f
    
    OPCODE_TEXT = 0x01
    CLOSE_CONN  = 0x8
    
    
    
    def handshake(client):
    	header=b""
    	while header.find(b'\r\n\r\n') == -1:
    		header += client.recv(16)
    	#print(header.decode())
    	lines = header.split(b"\r\n")
    	d=dict()
    	for line in lines[1:]:
    		if not line :continue
    		header,value = line.split(b": ",1)
    		d[header]=value
    
    	key = d[b'Sec-WebSocket-Key'].decode()
    
    	# compute Response Key
    	GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
    	hash = sha1(key.encode() + GUID.encode())
    	d=hash.digest()
    	response_key = b64encode(d).strip().decode('ASCII')
    	template='HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n'
    	handshake=template%response_key
    	client.send(handshake.encode())
    	print("handshake Done")
    
    def sendMessage(client,message):
    	global lock
    	header  = bytearray()
    	payload = message.encode('UTF-8')
    	payload_length = len(payload)
    	if payload_length <= 125:
    		header.append(FIN | OPCODE_TEXT)
    		header.append(payload_length)
    	#with lock:
    	client.send(header + payload)
    
    def readMessage(client,callback=lambda msg:print("receveid ",msg)):
    	b1, b2 = client.recv(2)
    	fin    = b1 & FIN
    	opcode = b1 & OPCODE
    	masked = b2 & MASKED
    	payload_length = b2 & PAYLOAD_LEN
    	if payload_length == 126:
    		#with lock:
    		payload_length = struct.unpack(">H", client.recv(2))[0]
    	elif payload_length == 127:
    		#with lock:
    		payload_length = struct.unpack(">Q", client.recv(8))[0]
    	#with lock:
    	masks = client.recv(4)
    	decoded = ""
    	#with lock:
    	data = client.recv(payload_length)
    	for char in data:
    		char ^= masks[len(decoded) % 4]
    		decoded += chr(char)
    
    	if callback:
    		callback(decoded)
    	return decoded
    
    
    
    	
    
    
    def thread_serve():
    	s=Server()
    	s.deinit()
    	start_new_thread(echoserve, (False,))
    
    def echoserve(blocking=True,port =9001):
    	lock = allocate_lock()
    	global sock
    	global serving
    	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    	sock.bind(("", port))
    	sock.listen()
    	sock.setblocking(blocking)
    	global client
    	print("waiting client at",port)
    	serving=True
    	while serving:
    		client = None
    		try:
    			with lock:
    				client, address = sock.accept()  
    		except socket.error as e:
    			if e.args[0]==11:
    				sleep_ms(1000)
    				continue
    			else:
    				print(e)
    		print("client connected ",address)
    		handshake(client)
    		break
    	print("End Thread Serving")
    	#client, address = sock.accept()  
    	client.setblocking(blocking)
    	while serving:
    		try:
    			with lock:
    				data = readMessage(client,None)
    		except ValueError:
    			sleep_ms(200)
    			continue
    		if data:
    			with lock:
    				sendMessage(client,"Echo "+data)
    			if data=="quit":
    				break
    	print("End Thread Listening")
    
    
    
    def stop():
    	global sock
    	global serving	
    	global client
    	serving=False
    	sock.close()
    	client.close()
    	s=Server()
    
    

    And the result error :

    >>> execfile("wsServer.py")
    >>> thread_serve()
    >>> waiting client at 9001
    client connected  ('192.168.4.2', 55233)
    handshake Done
    End Thread Serving
     
    >>> ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    ***ERROR*** A stack overflow in task Thread has been detected.
    

    My code works without thread.
    here client.html for testing, change ip according to your lopy ip :

    <html>
    <head>
      <title>Simple client</title>
    
      <script type="text/javascript">
    
        var ws;
        
        function init() {
    
          // Connect to Web Socket
          ws = new WebSocket("ws://192.168.4.1:9001/");
    
          // Set event handlers.
          ws.onopen = function() {
            output("onopen");
          };
          
          ws.onmessage = function(e) {
            // e.data contains received string.
            output("onmessage: " + e.data);
          };
          
          ws.onclose = function() {
            output("onclose");
          };
    
          ws.onerror = function(e) {
            output("onerror");
            console.log(e)
          };
    
        }
        
        function onSubmit() {
          var input = document.getElementById("input");
          // You can send message to the Web Socket using ws.send.
          ws.send(input.value);
          output("send: " + input.value);
          input.value = "";
          input.focus();
        }
        
        function onCloseClick() {
          ws.close();
        }
        
        function output(str) {
          var log = document.getElementById("log");
          var escaped = str.replace(/&/, "&amp;").replace(/</, "&lt;").
            replace(/>/, "&gt;").replace(/"/, "&quot;"); // "
          log.innerHTML = escaped + "<br>" + log.innerHTML;
        }
    
      </script>
    </head>
    <body onload="init();">
      <form onsubmit="onSubmit(); return false;">
        <input type="text" id="input">
        <input type="submit" value="Send">
        <button onclick="onCloseClick(); return false;">close</button>
      </form>
      <div id="log"></div>
    </body>
    </html>
    


  • Hello, i fllied a ticked :
    https://github.com/pycom/pycom-micropython/issues/47

    Testing with firmware 0.9.7 don't fix.
    I don't use garbage collector, and my code use only one thread.
    The error only occur after client connected in the message listen loop, and if i use the console.
    But server still running and working after error.
    I suspect interference with console or my own network because error occur only every 30 or 40 seconds

    Hope that it will be fixed by next Release ;-)
    Cheers



  • @matamune That's very likely. The best you can do is file a new ticket or if your are sure that it is the same issue add a comment on GitHub.



  • @sakis said in Thread WebSocketServer:

    Hi,

    The best place for reporting potential bugs is https://github.com/pycom/pycom-micropython/issues. Can you please file an issue there?

    Thank you

    Hi,
    I have the same issue with a thread with an infinite loop (to display digit on a 7 segments).

    Could it be related with the GC bug? (https://github.com/pycom/pycom-micropython/issues/39)



  • Hi,

    The best place for reporting potential bugs is https://github.com/pycom/pycom-micropython/issues. Can you please file an issue there?

    Thank you



Pycom on Twitter