Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
78 lines (71 sloc) 2.74 KB
'UDP request-response client.'
# Uses blocking sockets - however, I can't think of a situation where running
# several of these in parallel would be useful. (This is meant to be used
# primarily by nodes, not the master server.)
#
# I guess pinging multiple nodes simultaneously could be neat... But with since
# the nodes send updates to the master at most every ~30 minutes, why hurry?
#
# Besides, I'd have to make ping/SSH checks non-blocking too, which would raise
# the question of why I was re-writing the Twisted framework from the ground up?
#
# If the peers were linked in some kind of P2P network... All the layouts I
# considered had neighbourhoods far too small to be worth making non-blocking,
# though. Especially considering how cheap Python threads are.
#
# When I get around to passing tasks from the master server, I'll probably make
# that non-blocking.
import socket
import net
import traceback
import struct
BUFFSIZE=4096
def connect(hostname):
'Returns a socket on success, raises a socket.error on failure.'
#try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(net.timeout)
s.connect((hostname,net.port))
return s
#except:
#print 'Failed to connect to',hostname
#traceback.print_exc()
#raise socket.error('connect failed')
def ask(sock, request):
'Returns a response on success, raises a socket.error on failure.'
# prefix with length for TCP transit
request = struct.pack('!H', len(request)+2) + request
# send request
sent = sock.send(request)
while sent<len(request):
request=request[sent:]
sent = sock.send(request)
# receive response according to protocol definition in server.py
acc = ''
while 1:
chunk = sock.recv(BUFFSIZE)
if not chunk:
# check for 0-bytes-received disconnect
raise socket.error('response not received when asked')
acc += chunk
# NOTE: this function would be buggy if sending+receiving ever
# was asynchronous, due to accumulator losses on over-receives
# Luckily, a single-threaded request-response model prevents
# that from happening.
# check if an entire response has been accumulated
if len(acc)>2:
size = struct.unpack('!H',acc[:2])[0]
# pop it off and return it, if so
if len(acc)>=size:
response,acc = acc[:size],acc[size:]
return response[2:]
def close(sock):
'Probably optional, what with garbage collection and whatnot.'
# useful in some situations though
sock.shutdown(socket.SHUT_RDWR)
sock.close()
if __name__=='__main__':
import protocol.node
s=connect('127.0.1.1')
print ask(s, protocol.node.ping())
close(s)
Something went wrong with that request. Please try again.