Dataserver
Revision as of 15:38, 7 March 2008 by PeterHarding (talk | contribs)
dserver.py
#!/usr/bin/env python # # Purpose: Threaded data server implementation # # $Id:$ # #--------------------------------------------------------------------- """ Threaded server model Server side: open a socket on a port, listen for a message from a client, and accept a request and service it. The server spawns a thread to handle each client connection. Threads share global memory space with main thread; This is more portable than fork -- not yet on Windows; This version has been extended to use the standard Python logging module. Add the delimiter to the INI file to allow use of alternate delimiters in transmitted data - so data with embedded commas can be used. """ #--------------------------------------------------------------------- import os import csv import sys import getopt import thread import time import signal import logging #--------------------------------------------------------------------- from socket import * # get socket constructor and constants from datetime import datetime #--------------------------------------------------------------------- __version__ = "1.1.1" __id__ = "@(#) dserver.py [%s] 05/03/2008" daemon_flg = False debug_flg = False silent_flg = False terminate_flg = False verbose_flg = False wait_flg = False HOST = '' # Host server - '' means localhost PORT = 9578 # Listen on a non-reserved port number sockobj = None dserver_dir = None data_dir = None pid_path = None CONFIGFILE = "dserver.ini" LOGFILE = "dserver.log" PIDFILE = "dserver.pid" tables = [] INVALID = "INVALID" log = None #===================================================================== class Group: Name = None Idx = None Data = None def __init__(self, name): self.Name = name self.Idx = 0 self.Data = [] def __str__(self): s = "Grp %s Len %d" % (self.Name, len(self.Data)) return s def append(self, s): self.Data.append(s) def set(self): if len(self.Data) > 0: self.Idx = 0 else: self.Idx = -1 #--------------------------------------------------------------------- class Table: Count = 0 Valid = False Name = None Type = None Idx = None Data = None def __init__(self, name, type, delimiter=','): self.Name = name self.Type = type self.Delimiter = delimiter self.File = name + ".dat" self.Used = name + ".used" if self.Type == "CSV": rc = self.read_csv() elif self.Type == "Sequence": rc = self.read_sequence() elif self.Type == "Indexed": rc = self.read_indexed() elif self.Type == "Keyed": rc = self.read_keyed() if rc > 0: self.Valid = True try: self.ufh = open(self.Used, 'a+') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') sys.exit(1) #------------------------------------------------------------------ def __str__(self): s = "Table: %-10s Type: %-10s" % (self.Name, self.Type) if self.Valid: s += " * " if self.Type == "CSV": s += " %d rows" % len(self.Data) elif self.Type == "Sequence": s += " Starting value %d" % self.Data elif self.Type == "Indexed": s += " %d rows" % len(self.Data) elif self.Type == "Keyed": s += " %d groups" % len(self.Data) else: s += " " return s #------------------------------------------------------------------ def read_csv(self): try: f = open(self.File, 'r') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') sys.exit(1) self.Data = [] while True: line = f.readline() if not line: break line = line.strip() self.Data.append(line) f.close() self.Idx = 0 if debug_flg: INFO("Read in %d CSV rows - %s" % (len(self.Data), self.Name)) return len(self.Data) #------------------------------------------------------------------ def read_sequence(self): try: f = open(self.File, 'r') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') sys.exit(1) while True: line = f.readline() if not line: break line = line.strip() try: no = int(line) except: no = 0 self.Data = no f.close() return 1 #------------------------------------------------------------------ def read_keyed(self): try: f = open(self.File, 'r') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') sys.exit(1) groupName = None group = None self.Data = {} while True: line = f.readline() if not line: break line = line.strip() if (line.find("[") != -1): group_name = line.replace('[','').replace(']','') group = Group(group_name) self.Data[group_name] = group elif (line.find("#") != -1): continue elif (len(line) == 0): continue else: group.append(line) f.close() if debug_flg: INFO("Read in %d Keyed groups - %s" % (len(self.Data), self.Name)) return len(self.Data) #------------------------------------------------------------------ def read_indexed(self): try: f = open(self.File, 'r') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') sys.exit(1) self.Data = {} while True: line = f.readline() if not line: break line = line.strip() (no, data) = line.split(':') self.Data[no] = data f.close() if debug_flg: INFO("Read in %d indexed rows - %s" % (len(self.Data), self.Name)) return len(self.Data) #------------------------------------------------------------------ def flush(self): if not self.Valid: return ts = datetime.now().strftime('%Y%m%d%H%M%S') self.BackupCmd = "cp %s.dat %s.%s" % (self.Name, self.Name, ts) if self.Type == "CSV": self.flush_csv() elif self.Type == "Sequence": self.flush_sequence() elif self.Type == "Indexed": self.flush_indexed() elif self.Type == "Keyed": self.flush_keyed() #------------------------------------------------------------------ def flush_csv(self): os.system(self.BackupCmd) try: f = open(self.File, 'wb') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') return 0 i = self.Idx while i < len(self.Data): f.write("%s\n" % self.Data[i]) i += 1 f.close() #------------------------------------------------------------------ def flush_sequence(self): os.system(self.BackupCmd) try: f = open(self.File, 'wb') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') return 0 f.write("%d\n" % self.Data) f.close() #------------------------------------------------------------------ def flush_keyed(self): os.system(self.BackupCmd) try: f = open(self.File, 'wb') except IOError, e: sys.stderr.write('[dserver] Open failed: ' + str(e) + '\n') return 0 group_keys = self.Data.keys() group_keys.sort() for key in group_keys: f.write("[%s]\n" % key) group = self.Data[key] i = group.Idx while i < len(group.Data): f.write("%s\n" % group.Data[i]) i += 1 f.write("\n") f.close() #------------------------------------------------------------------ def flush_indexed(self): pass #===================================================================== def INFO(msg): if log: log.info(' ' + msg) if verbose_flg: print "[dserver] %s" % msg #--------------------------------------------------------------------- def ERROR(msg): if log: log.error(msg) sys.stderr.write('[dserver] %s\n' % msg) #--------------------------------------------------------------------- def WARNING(msg): if log: log.warning('*****' + msg + '*****') if verbose_flg: print "[dserver] %s" % msg #===================================================================== def read_config(): config_file = data_dir + CONFIGFILE try: f = open(config_file, 'r') except IOError, e: ERROR('Open failed: ' + str(e)) sys.exit(1) definition_flg = False while True: line = f.readline() if not line: break line = line[:-1] line = line.replace('\r','') line = line.strip() if (line.find("#") != -1): continue if (line.find("[Data]") != -1): definition_flg = True elif (line.find("Description=") != -1): description = line.split("=") (name, type, delimiter) = description[1].split(":") t = Table(name, type, delimiter) INFO(str(t)) tables.append(t) f.close() #--------------------------------------------------------------------- def get_table_index(name): for i in range(len(tables)): if (tables[i].Name == name): return i return -1 #--------------------------------------------------------------------- def process(str): msg = str.split("|") l = len(msg) if debug_flg: INFO("[dserver::process] len %d msg %s" % (l, msg)) ts = datetime.now().strftime('%Y%m%d%H%M%S') reply = "None" if (msg[0] == "REG"): name = msg[1].replace('\n','').replace('\r','') idx = get_table_index(name) if debug_flg: INFO("[dserver::process] REG '%s' -> %d" % (name, idx)) reply = "%d" % idx elif (msg[0] == "REGK"): if (len(msg) != 3): if debug_flg: ERROR("Bad Message", msg) elif (msg[0] == "REGI"): if (len(msg) != 2): if debug_flg: ERROR("Bad Message", msg) elif (msg[0] == "GETN"): if (len(msg) != 2): if debug_flg: ERROR("Bad Message", msg) hdl = int(msg[1]) try: t = tables[hdl] except: t = None if t != None: if t.Type == 'CSV': if (t.Idx < len(t.Data)): reply = t.Data[t.Idx] t.Idx += 1 else: reply = "*Exhausted*" elif t.Type == "Sequence": reply = "%d" % t.Data t.Data += 1 else: reply = "UNKNOWN" t.ufh.write("%s - %s" % (ts, reply)) if debug_flg: INFO("[dserver::process] GETN -> %s" % reply) elif (msg[0] == "GETK"): if (len(msg) != 3): if debug_flg: ERROR("Bad Message", msg) hdl = int(msg[1]) grp = msg[2] try: t = tables[hdl] except: t = None if t != None: try: g = t.Data[grp] except: g = None if g != None: if (g.Idx < len(g.Data)): reply = g.Data[g.Idx] g.Idx += 1 else: reply = "*Exhausted*" t.ufh.write("%s - %s:%s" % (ts, grp, reply)) elif (msg[0] == "GETI"): if (len(msg) != 3): if debug_flg: ERROR("Bad Message", msg) hdl = int(msg[1]) idx = msg[2] try: t = tables[hdl] except: t = None if t != None: try: reply = t.Data[idx] except: reply = "UNDEFINED" t.ufh.write("%s - %s:%s" % (ts, idx, reply)) elif (msg[0] == "STOC"): if (len(msg) != 3): if debug_flg: ERROR("Bad Message", msg) hdl = int(msg[1]) data = msg[2] reply = "0" try: t = tables[hdl] except: t = None if t != None: s = t.Data.append(data) if debug_flg: INFO(t.Data) reply = "1" elif (msg[0] == "STOK"): if (len(msg) != 4): if debug_flg: ERROR("Bad Message", msg) hdl = int(msg[1]) grp = msg[2] data = msg[3] reply = "0" try: t = tables[hdl] except: t = None if t != None: try: g = t.Data[grp] except: g = None if g != None: data = g.Data.append(data) reply = "1" return reply #--------------------------------------------------------------------- def sig_term(signum, frame): "SIGTERM handler" shutdown() #--------------------------------------------------------------------- def shutdown(): INFO("Server shutdown at %s" % datetime.now()) for i in range(len(tables)): tables[i].flush() try: os.unlink(pid_path) except IOError, e: ERROR('Unlink failed: ' + str(e)) sys.exit(1) sys.exit(0) #--------------------------------------------------------------------- def check_running(): try: pfp = open(pid_path, 'r') except IOError, (errno, strerror): pfp = None # ERROR("I/O error(%s): %s" % (errno, strerror)) except: ERROR("Unexpected error:", sys.exc_info()[0]) raise if pfp: line = pfp.readline() line = line.strip() dserver_pid = int(line) noProcess = 0 try: os.kill(dserver_pid, 0) except OSError, e: if e.errno == 3: noProcess = 1 else: ERROR("kill() failed:" + str(e)) sys.exit(0) if noProcess: INFO("[dserver] Stale dserver pid file!") pfp.close() os.unlink(pid_path) return None else: pfp.close() return dserver_pid return dserver_pid else: return None #--------------------------------------------------------------------- def create_pidfile(): pid = os.getpid() try: pfp = open(pid_path, 'w') except IOError, e: ERROR("Open failed - " + str(e)) sys.exit(0) pfp.write("%d" % pid) pfp.close() INFO("Running server with PID -> %d" % pid) return pid #--------------------------------------------------------------------- def become_daemon(): pid = os.fork() if pid == 0: # In child pid = create_pidfile() time.sleep(1) elif pid == -1: # Should not happen! ERROR("fork() failed!") time.sleep(1) sys.exit(0) else: # In Parent time.sleep(1) sys.exit(0) time.sleep(2) os.setsid() return pid #--------------------------------------------------------------------- def init(): pid = check_running() if pid: print "[dserver] Server already running! (pid = %d)" % pid sys.exit(0) if daemon_flg: pid = become_daemon() else: pid = create_pidfile() global log log = logging.getLogger('dserver') hdlr = logging.FileHandler(LOGFILE) fmtr = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(fmtr) log.addHandler(hdlr) log.setLevel(logging.INFO) INFO("Started processing") read_config() if (not silent_flg): INFO("Server PID is %d" % pid) #--------------------------------------------------------------------- def terminate(): dserver_pid = check_running() if dserver_pid: if (not silent_flg): INFO("Terminating server with pid, %d" % dserver_pid) os.kill(dserver_pid, signal.SIGTERM) if (wait_flg): while True: try: kill(dserver_pid, 0) except OSError, e: if e.errno == 3: break else: ERROR("kill() failed:" + str(e)) sys.exit(0) time.sleep(1) return 0 #==== Socket Server ================================================== def init_connection(): global sockobj sockobj = socket(AF_INET, SOCK_STREAM) # make a TCP socket object sockobj.bind((HOST, PORT)) # bind it to server port number sockobj.listen(10) # allow upto 10 pending connects #--------------------------------------------------------------------- def handle_client(connection): # in spawned thread: reply while True: # read, write a client socket try: request = connection.recv(1024) except: break if debug_flg: INFO('[dserver] Request -> "%s"' % request) if not request: break reply = process(request) if debug_flg: INFO('[dserver] Reply -> "%s"' % reply) connection.send(reply) connection.close() #--------------------------------------------------------------------- def dispatcher(): while True: # Wait for next connection, connection, address = sockobj.accept() INFO('Host (%s) - Connected at %s' % (address[0], datetime.now())) thread.start_new(handle_client, (connection,)) #===================================================================== def main(): global daemon_flg global debug_flg global terminate_flg global verbose_flg global wait_flg global dserver_dir global data_dir global pid_path try: opts, args = getopt.getopt(sys.argv[1:], "dDsTvVw?") except getopt.error, msg: print __doc__ return 1 try: dserver_dir = os.environ["DSERVER_DIR"] except KeyError, e: print "Set DSERVER_DIR environment variable and rerun!" return 1 data_dir = dserver_dir + '/DATA/' pid_path = data_dir + PIDFILE wrk_path = os.getcwd() wrk_dir = os.path.basename(wrk_path) os.chdir(data_dir) for o, a in opts: if o == '-d': debug_flg = True elif o == '-D': daemon_flg = True elif o == '-s': tsilent_flg = True elif o == '-T': terminate_flg = True elif o == '-v': verbose_flg = True elif o == '-V': print "[dserver] Version: %s" % __version__ return 1 elif o == '-w': wait_flg = True elif o == '-?': print __doc__ return 1 print "[dserver] Server working directory is %s" % os.getcwd() if terminate_flg: terminate() return 0 if (debug_flg): print "Debugging %s" % debug_flg if args: for arg in args: print arg signal.signal(signal.SIGTERM, sig_term) init() init_connection() dispatcher() return 0 #--------------------------------------------------------------------- if __name__ == '__main__' or __name__ == sys.argv[0]: try: sys.exit(main()) except KeyboardInterrupt, e: print "[dserver] Interrupted!" shutdown() #--------------------------------------------------------------------- """ Revision History: Date Who Description -------- --- -------------------------------------------------- 20031014 plh Initial implementation Problems to fix: To Do: Issues: """
Download data server data
dcl.py
#!/usr/bin/env python # # Author: Peter Harding <plh@pha.com.au> # P. L. Harding & Associates Pty. Ltd. # P. O. Box 6195, # MELBOURNE, VIC, 3004 # # Phone: 03 9641 2222 # Fax: 03 9641 2200 # Mobile: 0418 375 085 # # Copyright (C) 1994-2003, Peter Harding # # @(#) [1.3.12] dsvtst.py 01/01/2003 # # $Id:$ # #--------------------------------------------------------------------- """ Python implementation of DataServer client API """ #--------------------------------------------------------------------- import os import sys import getopt #--------------------------------------------------------------------- from socket import * # portable socket interface plus constants #--------------------------------------------------------------------- __version__ = "1.0.0" HOST = 'localhost' PORT = 9578 #--------------------------------------------------------------------- class dcl: DELIM = ',' ServerHostname = None # server name, default to 'localhost' ServerPort = None # non-reserved port used by the server sockobj = None Fields = None def __init__(self, server=HOST, port=PORT): "Initialize TCP/IP socket object and make connection to server:port" self.ServerHostname = server self.ServerPort = port self.sockobj = socket(AF_INET, SOCK_STREAM) self.sockobj.connect((self.ServerHostname, self.ServerPort)) #------------------------------------------------------------------ def Get(self, s): "Send s to server and get back response" if self.sockobj != None: self.sockobj.send(s) data = self.sockobj.recv(1024) print '[dcl::Get] Client received:', `data` return data else: return None #------------------------------------------------------------------ def Close(self): "close socket to send eof to server" if self.sockobj != None: self.sockobj.close() self.sockobj = None #------------------------------------------------------------------ def RegisterType(self, type): msg = "REG|%s" % type try: handle = int(self.Get(msg)) except: handle = -1 return handle #------------------------------------------------------------------ def GetNext(self, typeRef): msg = "GETN|%d" % typeRef csv_data = self.Get(msg) data = csv_data.split(',') return data #------------------------------------------------------------------ def GetNextKeyed(self, typeRef, key): msg = "GETK|%d|%s" % (typeRef, key) csv_data = self.Get(msg) data = csv_data.split(',') return data #------------------------------------------------------------------ def GetNextIndexed(self, typeRef, idx): msg = "GETI|%d|%s" % (typeRef, idx) csv_data = self.Get(msg) data = csv_data.split(',') return data #------------------------------------------------------------------ def StoreCsvData(self, typeRef, csv_data): msg = "STOC|%d|%s" % (typeRef, csv_data) reply = self.Get(msg) try: rc = int(reply) except: rc = -1 return rc #------------------------------------------------------------------ def StoreKeyedData(self, typeRef, keyRef, csv_data): msg = "STOK|%d|%s" % (typeRef, keyRef, csv_data) reply = self.Get(msg) try: rc = int(reply) except: rc = -1 return rc #------------------------------------------------------------------ def GetField(self, typeRef, i): if (i < len(self.Field[i])): return self.Field[i] else: return None #--------------------------------------------------------------------- def main(): global debugFlg global verboseFlg try: opts, args = getopt.getopt(sys.argv[1:], "dvV?") except getopt.error, msg: print __doc__, return 1 for o, a in opts: if o == '-d': debugFlg = 1 elif o == '-v': verboseFlg = 1 elif o == '-V': print "Version: %s" % __version__ return 0 elif o == '-?': print __doc__() return 0 if args: for arg in args: print "[dcl] %s" % arg else: pass #--------------------------------------------------------------------- if __name__ == '__main__' or __name__ == sys.argv[0]: sys.exit(main()) #--------------------------------------------------------------------- """ Revision History: Date Who Description -------- --- -------------------------------------------------- 20031014 plh Initial implementation Problems to fix: To Do: Issues: """
dsvtst.py
#!/usr/bin/env python # # Author: Peter Harding <plh@pha.com.au> # P. L. Harding & Associates Pty. Ltd. # P. O. Box 6195, # MELBOURNE, VIC, 3004 # # Phone: 03 9641 2222 # Fax: 03 9641 2200 # Mobile: 0418 375 085 # # Copyright (C) 1994-2003, Peter Harding # # @(#) [1.3.12] dsvtst.py 01/01/2003 # # $Id:$ # #--------------------------------------------------------------------- """ Python implementation of Data Server test Usage: dsvtst.py -t <table> [-k <key>] The '-t <table>' option is used to specift the name of the table to query The '-i <index>' specifies the index for the indexed data type The '-k <key>' specifies the key for the keyed data type """ #--------------------------------------------------------------------- import os import sys import getopt import dcl #--------------------------------------------------------------------- __version__ = "1.0.0" #--------------------------------------------------------------------- table_name = "Address" indexed = 0 indexNo = 0 keyed = 0 key_name = None key_ref = None store_flg = 0 store_data = None debug_flg = 0 term_flg = 0 verbose_flg = 0 #--------------------------------------------------------------------- def process(): ds = dcl.dcl() if (ds == None): print("Connection to data server failed - is data server process running?\n") return 1 type_ref = ds.RegisterType(table_name) pid = os.getpid() print "My PID is %d" % pid print "Data type \"%s\" registered as %d" % (table_name, type_ref) if (store_flg): if keyed: ds.StoreKeyedData(type_ref, key_ref, store_data) else: ds.StoreCsvData(type_ref, store_data) else: if keyed: sp = ds.GetNextKeyed(type_ref, key_name) elif indexed: sp = ds.GetNextIndexed(type_ref, indexNo) else: sp = ds.GetNext(type_ref) if (sp): print "Buffer is \"%s\"" % sp if sp != None: if len(sp) > 0: for i in range(len(sp)): print "Field %2d: \"%s\"" % (i, sp[i]) else: print "Field: \"%s\"" % None else: print "Type %d exhausted" % (pid, type_ref) # } #--------------------------------------------------------------------- def main(): global debug_flg global term_flg global verbose_flg global indexed global indexNo global keyed global key_name global table_name global store_flg global store_data try: opts, args = getopt.getopt(sys.argv[1:], "di:k:s:t:TvV?") except getopt.error, msg: print __doc__, return 1 for o, a in opts: if o == '-d': debug_flg = 1 elif o == '-i': indexed = 1 indexNo = int(a) elif o == '-k': keyed = 1 key_name = a elif o == '-t': table_name = a elif o == '-T': term_flg = 1 elif o == '-s': store_flg = 1 store_data = a elif o == '-v': verbose_flg = 1 elif o == '-V': print "Version: %s" % __version__ return 0 elif o == '-?': print __doc__() return 0 if args: for arg in args: print arg else: pass process() #--------------------------------------------------------------------- if __name__ == '__main__' or __name__ == sys.argv[0]: sys.exit(main()) #--------------------------------------------------------------------- """ Revision History: Date Who Description -------- --- -------------------------------------------------- 20031014 plh Initial implementation Problems to fix: To Do: Issues: """
Data
dserver.ini
#----- Example dserver data files -------------------------- [Data] Description=Address:CSV:| # Description=Stock:CSV:, Description=Sequence:Sequence: Description=Indexed:Indexed:, Description=Keyed:Keyed:,
Address.dat
Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 Level 21,150 Lonsdale Street,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000 AAA,Melbourne,Victoria,3000 BBB,Melbourne,Victoria,3000 CCC,Melbourne,Victoria,3000
Keyed.dat
[a100] AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC [a101] AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC [b100] AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC AAA,BBB,CCC
Makefile
reset: cp Address.master Address.dat cp Indexed.master Indexed.dat cp Keyed.master Keyed.dat cp Sequence.master Sequence.dat
Python ctypes Client
This uses the Windows DLL implemented below as MS Visual Studio 2005 project(s).
#!/usr/bin/env python import sys import ctypes import pprint dserver = ctypes.CDLL('dcl') pprint.pprint(dserver.__dict__) print type(dserver) dserver.dsInit.restype = ctypes.c_char_p dserver.dsInit.argtypes = [ctypes.c_char_p, ctypes.c_int] dserver.dsRegister.restype = ctypes.c_int dserver.dsRegister.argtypes = [ctypes.c_char_p] dserver.dsGetNext.restype = ctypes.c_char_p dserver.dsGetNext.argtypes = [ctypes.c_int] dserver.dsGetKeyed.restype = ctypes.c_char_p dserver.dsGetKeyed.argtypes = [ctypes.c_int, ctypes.c_char_p] dserver.dsGetIndexed.restype = ctypes.c_char_p dserver.dsGetIndexed.argtypes = [ctypes.c_int, ctypes.c_int] dserver.dsStore.restype = ctypes.c_int dserver.dsStore.argtypes = [ctypes.c_int, ctypes.c_char_p] s= 100 * ' ' dserver.get_buffered(1, s, 100) print s dserver.dsInit('localhost', 9578) dx = dserver.dsRegister('Sequence') dserver.dsGetNext(idx)
MS Visual C Client DLL and Test harness
Here are the zipped up project files...