"Bjoern Schliessmann" <usenet-mail,,...m> wrote: >I'm currently trying to implement a simulation program with Kamaelia >and need a reliable TCP connection to a data server. > >From Twisted, I know that a method is called if the connection fails >by whatever reason. I tried to get the same results with Kamaelia's >TCPClient component. If I start up the component and try to connect >to a closed TCP port it fails and sends a message out of the signal >box, that's okay. > >But if the connection attempt succeeds and, after some time, the >server drops the connection with full TCP handshake (FIN, FIN+ACK, >ACK), the component just hangs and does nothing. Is this by design, >or could there be an error in my setup? >
Not sure about Kamelia, but I have found that when a FIN comes along, a socket.recv() gives back an empty string, just like EOF on a file. I always have my sockets unblocked and fitted with time outs, but then I am basically a broken down assembler programmer, so there are probably better techniques around. Below is what I use - a sort of netstring, synced on a tilde, with human readable length implementation and escaping of tildes and the escape character. It seems to work reliably for me, and detects when the server goes down. The code for a typical client is below. If anybody is interested I will post the server too, but it should be trivial to make, given the example below. I hope the tabs survive the journey - Hendrik #start of code fragment def sockget_len(s,L,data): """ This fills a buffer of given length from the socket s, recursively. s is the socket L is the length to receive data is the buffer """ error = 0 req_L = L - len(data) try: data = data+s.recv(req_L) except socket.error,msg: # broken pipes again if 'timed out' in msg: rec = '2'*L return 2,rec # time out print 'socket error while receiving',msg rec = '1'*L return 1,rec # error = 1 is a snafu if not data: print 'end of file while receiving' rec = '0'*L return 3,rec # This is end of file if len(data) != L: error,data = sockget_len(s,L,data) return error,data def sockget(s): """ Gets a transmission from host. """ while True: tilde = '' error,tilde = sockget_len(s,1,tilde) # sync up on tilde if error == 1: return error,'' elif error == 2: return error,'' elif error == 3: return error,'' if tilde == '~': break length = '' error,length = sockget_len(s,4,length) # get the length of the data if error == 1: return error,'' # real error elif error == 2: return error,'' # Time out elif error == 3: return error,'' # End of file L = int(length) buf = '' error,data = sockget_len(s,L,buf) # get the data of length L return error, data # same errors as above 0 is all right # client communications program def comms_thread(qi,qo): """This listens for the latest values, and sends requests up.""" while True: HOST = 'Linuxbox' # The remote host PORT = 50007 # The same port as used by the server socket.setdefaulttimeout(10.00) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) while True: try: qi.put('Connecting,') s.connect((HOST, PORT)) break except socket.error,msg: print 'error msg is:',msg time.sleep(10) continue print 'Connected - Time out is:',s.gettimeout() qi.put('Connected,') last_rx_time = time.time() last_tx_time = time.time() while True: while True: error,data = sockget(s) # see if a message from host if error == 0 and data: msg2 = data.replace('/\x81','~') msg1 = msg2.replace('/\xd0','/') qi.put(msg1) print 'received',msg1 last_rx_time = time.time() break elif error == 1: print 'Error after sockget' break if time.time() - last_rx_time > 180: print 'no comms from host for 3 minutes' error = 1 break # time out ok, unless they are too long if error == 2: error = 0 # time outs are all right here break if error == 3: error = 1 break # end of files are a snafu if error == 1: break try: i_string = qo.get(block=False) # see if stuff to transmit except Queue.Empty: if time.time()-last_tx_time > 8.5: i_string = 'Keepalive' # if not for a while, tell server we are alive print 'sending keepalive' else: time.sleep(0.1) # else wait a while and carry on continue msg1 = i_string.replace('/','/\xd0') msg2 = msg1.replace('~','/\x81') length = str(len(msg2)) L = len(length) if L == 1: length = '000'+length elif L == 2: length = '00'+length elif L == 3: length = '0'+length try: s.send('~'+length+msg2) last_tx_time = time.time() except socket.error,msg: print 'Socket error on transmit',msg break time.sleep(0.1) s.close() # Formally close the broken thing qi.put('Quit,') # Tell main thread its hopeless sys.exit() # Clobber this thread -- http://mail.python.org/mailman/listinfo/python-list