H J van Rooyen
1/12/2008 8:45:00 AM
"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