need a thread to keep a socket connection alive?

N

nephish

hey there,

i have a script that waits for message packets from a data server over
a socket.
it goes a little like this:

while 1:
x+=1
databack = sockobj.recv(158)
if databack:

print 'caught a message %s bytes ' % len(databack)
if len(databack) > 120:
message = databack[3:-3] #strip stx and enx
print '\n\n%s' % message
else:
break
print 'end data ack'


it works fine for a while, but the server requires that i send a
heartbeat ping every 600 seconds or it will terminate the connection.

so i also need something like
while 1:
sockobj.send(ping)
ping_acknowlage = sockobj.recv(48)
time.sleep(550)



should i do this with threads? i dont want to interrupt the listening
cycle to send a ping.

appreciate any tips on how would be the best way to pull this off.
 
R

Rene Pijlman

(e-mail address removed):
i have a script that waits for message packets from a data server over
a socket.

Using what network protocol?
it works fine for a while, but the server requires that i send a
heartbeat ping every 600 seconds or it will terminate the connection. [...]
should i do this with threads? i dont want to interrupt the listening
cycle to send a ping.

If this is a TCP connection with a conversational protocol, you can't have
two threads reading bytes of the socket, without some sort of
coordination. When one thread parses the bytes it received, some bytes may
be part of the next message for the other thread.

You may be better off with asynchronous I/O and a state machine model.
http://squirl.nightmare.com/medusa/async_sockets.html
http://www.python.org/doc/lib/module-asyncore.html
http://twistedmatrix.com/projects/core/documentation/howto/clients.html
 
N

nephish

thanks for the info, i will likely use the first link you posted with
the async module just to get it going, but i want to learn more about
twisted for later. there is even an O'Reilly book on it i see.
thanks for the tips,
sk
 
B

Ben Sizer

i have a script that waits for message packets from a data server over
a socket.

If you're using TCP, bear in mind that you do not receive packets - you
receive a stream of data, which may usually come in the same quantities
as it was sent, but not always. If you don't take that into account,
you may end up missing a valid message because it arrived in several
parts.
it works fine for a while, but the server requires that i send a
heartbeat ping every 600 seconds or it will terminate the connection.

It is probably worth just reconnecting if necessary. After all, you
could be disconnected for other reasons too.
 
R

Roy Smith

hey there,

i have a script that waits for message packets from a data server over
a socket.
it goes a little like this:

while 1:
x+=1
databack = sockobj.recv(158)
if databack:

print 'caught a message %s bytes ' % len(databack)
if len(databack) > 120:
message = databack[3:-3] #strip stx and enx
print '\n\n%s' % message
else:
break
print 'end data ack'

You need to go review how TCP works. All that it guarantees is that you
will receive bytes in the same order they were sent. It says nothing about
maintaining record boundaries. Just because you did a send(n) at one end,
it doesn't mean that you can expect to read n bytes in a single recv() call
at this end. Multiple send() calls could have their contents accumlated
into a single recv() call, or a single send() could get broken up into
several recv() calls.

If you want to read fixed-length messages (as you appear to be trying to do
with your recv(158)), you need to build a buffering layer which reads from
the socket into a buffer and then doles out messages to a higher layer from
that buffer.
it works fine for a while, but the server requires that i send a
heartbeat ping every 600 seconds or it will terminate the connection.

so i also need something like
while 1:
sockobj.send(ping)
ping_acknowlage = sockobj.recv(48)
time.sleep(550)

This needs to be burried in a lower layer as well. You want to build some
kind of bufferedConnection class which hides all this gunk from your
application. You probably will want sendMessage() and recvMessage()
methods for your class. You probably want to have this class create a
thread to handle the low-level I/O asyncronously, and put the heatbeat
processing in there.

This is not a trivial problem. By the time you're done with it, you will
have learned a lot about how to communicate over a network.
 
F

Fredrik Lundh

Roy said:
If you want to read fixed-length messages (as you appear to be trying to do
with your recv(158)), you need to build a buffering layer which reads from
the socket into a buffer and then doles out messages to a higher layer from
that buffer.
This is not a trivial problem. By the time you're done with it, you will
have learned a lot about how to communicate over a network.

however, creating a buffered layer for reading is a trivial problem: just call
makefile on the socket object, and use the resulting object as a file handle:
'Last-Modified: Mon, 24 Apr 2006 04:52:53 GMT\r\n'

etc.

</F>
 
R

Roy Smith

Fredrik Lundh said:
however, creating a buffered layer for reading is a trivial problem: just call
makefile on the socket object, and use the resulting object as a file handle:

The problem with that is that makefile() requires the socket to be in
blocking mode. If you're going to be implementing heartbeat, that's
probably not what you want.
 
S

Serge Orlov

hey there,

i have a script that waits for message packets from a data server over
a socket.
it goes a little like this:

while 1:
x+=1
databack = sockobj.recv(158)
if databack:

print 'caught a message %s bytes ' % len(databack)
if len(databack) > 120:
message = databack[3:-3] #strip stx and enx
print '\n\n%s' % message
else:
break
print 'end data ack'


it works fine for a while, but the server requires that i send a
heartbeat ping every 600 seconds or it will terminate the connection.

so i also need something like
while 1:
sockobj.send(ping)
ping_acknowlage = sockobj.recv(48)
time.sleep(550)



should i do this with threads? i dont want to interrupt the listening
cycle to send a ping.

appreciate any tips on how would be the best way to pull this off.

sockobj.settimeout(550)

before the loop and later in the loop:

try:
databack = sockobj.recv(158)
except socket.timeout:
ping_server(sockobj)
continue

Also, as other people pointed out, you'd better make buffered socket
with .makefile() socket method.
 
R

Roy Smith

Serge Orlov said:
sockobj.settimeout(550)
[...]
Also, as other people pointed out, you'd better make buffered socket
with .makefile() socket method.

If I understand the docs for the socket module correctly, these two
suggestions are mutually incompatable.
 
S

Serge Orlov

Roy said:
Serge Orlov said:
sockobj.settimeout(550)
[...]
Also, as other people pointed out, you'd better make buffered socket
with .makefile() socket method.

If I understand the docs for the socket module correctly, these two
suggestions are mutually incompatable.

Perhaps this restriction was lifted?

Traceback (most recent call last):
File "<pyshell#21>", line 1, in -toplevel-
f.readline()
File "C:\Python24\lib\socket.py", line 340, in readline
data = self._sock.recv(self._rbufsize)
timeout: timed out
 
N

nephish

ok, thanks for all the suggestions, gents, i clearly have more to read
on this.
i have discovered that the server will send a request for the heartbeat
ping if its almost timed out, so i use the length of the message to
determine what to do with it.

msg = sockobj.recv(1024)

if len(msg) == 158:
record the data
elif len(msg) == (34): # length of request for ping
ping the server
else:
yada yada.

each real message ( according to their docs ) should be exactly 158
bytes.

i know i need to look more into all of this.. but thanks for all of
your help

-shawn
 
R

Roy Smith

elif len(msg) == (34): # length of request for ping
ping the server

This seems really dangerous. You are obviously writing to some
already defined (and hopefully, documented) protocol. What does the
protocol spec say about ping request messages?

I would be very surprised if the spec says that a ping request is
defined as any message which is 34 bytes long. More likely, it says
something like, "A ping request is defined by the command code being
set to 5" or something like that. That's what you should be testing,
not the length of the message.
 
R

Rene Pijlman

(e-mail address removed):
i have discovered that the server will send a request for the heartbeat
ping if its almost timed out, so i use the length of the message to
determine what to do with it.

msg = sockobj.recv(1024)

if len(msg) == 158:
record the data
elif len(msg) == (34): # length of request for ping
ping the server

Incorrect. There are no 'messages' with TCP, only bytes.
 
N

nephish

ok, every message starts with "ENX" and ends with "STX"
in between are several parts. the first is the message length sent as
an unsigned long int (according to the docs) this is four bytes. The
next is the message type - another 4 bytes that corrospond to a certain
chart. for example, the login is message type 200. Then there is the
message. different messages have different lengths and types.
the data part, i am still trying to break apart. Some of it (when
printed to the screen) is a string, then some very funny characters,
then another string, then more funny looking characters, then 'ETX'

up untill now, all i have had to process is the strings, so i split the
message up, and used the strings as my data. But now, i do need the
other info. -whew.

i guess i am learning a lot. i just ordered Python Essential Reference
from amazon. ;)

anyway. from what i have found on line, i am going to be using the
struct module.



oh, that was a typo earlier. not 34 bytes, but 14.
the data comming in is alway in 158 bytes though.

thanks guys.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top