How to handle sockets - easily?
Bubba
nickname at banelli.biz.invalid
Wed Feb 16 12:26:40 EST 2011
Richard Kettlewell's log on stardate 10 vlj 2011
> Rewrites can help but they can also go badly wrong. Rewriting into a
> language you don't yet know seems especially likely to fall into the
> latter category!
Indeed.
However, it seems to be quite "doable", as it took me from 0 knowledge
of Python to come up with a solution that does only part of the thing
(it's missing CRC check for GPS data and NMEA checksum, user control
for changing device setup on the fly via web and few more details).
Here's the code (ATTN: may wrap):
#! /usr/bin/env python
import asyncore
import socket
import string
import MySQLdb
import sys
class Handler(asyncore.dispatcher_with_send):
def handle_read(self):
data = self.recv(128) #payload size
data = string.lstrip(data,"\n") #sometimes a 0xOA stays
data_len = len (data) #get payload length
trackerID_hex = data[4:11] #tracker ID
trackerID = "" #create empty string
for i in trackerID_hex:
trackerID += str('%02X'%ord(i)) #convert hex integer to string and append to trackerID
trackerID = string.rstrip(trackerID,"F") #remove stuffed F's from tracker ID
checksum = ""
checksum_hex = data[data_len-4:data_len-1] #second part of command payload, checksum
for i in checksum_hex:
checksum += str('%02X'%ord(i)) #convert hex integer to string and append to trackerID
GPSdata = data[13:data_len-4] #GPRMC - hhmmss.dd,S,xxmm.dddd,<N|S>,yyymm.dddd,<E|W>,s.s,h.h,ddmmyy
l = list()
l = string.split(GPSdata, ",")
n = len(l)
if n > 1: #hack! devices can mess the output, so just discard the data and go to another sample
GPStime = l[0]
GPStime = GPStime[0:2] + ":" + GPStime[2:4] + ":" + GPStime[4:6]
GPSstatus = l[1]
GPSlatitude = l[2]
GPSlatitude = float(GPSlatitude[0:2]) + float(GPSlatitude[2:10]) / 60
GPSNS = l[3]
GPSlongitude = l[4]
GPSlongitude = float(GPSlongitude[0:3]) + float(GPSlongitude[3:11]) / 60
GPSEW = l[5]
try:
GPSspeed = float(l[6])
except ValueError:
GPSspeed = 0
GPSspeed *= 1.852
try:
GPSheading = float(l[7])
except ValueError:
GPSheading = 0
GPSdate = l[8]
GPSdate = "20" + GPSdate[4:6] + "-" + GPSdate[2:4] + "-" + GPSdate[0:2]
try:
conn = MySQLdb.connect (host = "localhost", user = "", passwd = "", db = "") #:p
except MySQLdb.Error, e:
print "Error %d: %s" % (e.args[0], e.args[1])
sys.exit (1)
cursor = conn.cursor()
query = "INSERT INTO data (trackerID, GPStime, GPSstatus, GPSlatitude, GPSNS, GPSlongitude, GPSEW, GPSspeed, GPSheading, GPSdate) VALUES ('" + trackerID + "', '" + GPStime + "', '" + GPSstatus + "', '" + str(GPSlatitude) + "', '" + GPSNS + "', '" + str(GPSlongitude) + "', '" + GPSEW + "', '" + str(GPSspeed) + "', '" + str(GPSheading) + "', '" + GPSdate + "')"
cursor.execute (query)
cursor.close ()
conn.commit()
conn.close ()
class Server(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accept(self):
pair = self.accept()
if pair is None:
pass
else:
sock, addr = pair
print 'Incoming connection from %s' % repr(addr)
handler = Handler(sock)
server = Server('', 2020)
asyncore.loop()
C code did not parse data, but rather put the whole payload to SQL
database, which would be parsed afterwards. This code takes almost
twice LOC less that C code.
I do, however, have some more questions (thus crosspost to
comp.lang.python) - how many connections can this server handle without
a problem? I'm using Asyncore module, as it can be seen.
Is it necessary, due to the fact that it should serve more than
thousand devices that send data every 10 seconds, to do threading (I
believe that is already done with Asyncore for sockets, but what about
SQL?)
Any other general code suggestions (since this is the first time I
write anything in Python)?
TIA!
--
"If you lie to the compiler,
it will get its revenge."
Henry Spencer
2.718281828459045235360287471352662497757247093699959574966967627.com
More information about the Python-list
mailing list