How to handle sockets - easily?

Bubba nickname at banelli.biz.invalid
Wed Feb 16 18:26:40 CET 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