Upgrading from 7.9.10 to 8.1.12 broke the socket() connection to a Ziath scanner

A customer recently upgraded from 7.9.10 to 8.1.12 which upgraded Jython from 2.5 to 2.7 from what I can gather. They were using some socket() functions to talk to this Ziath scanner here:

After the Gateway upgrade we found that the max size of the data response we can get is 503 bytes. Their scripts from what I can see don’t make sense in 7.9.10 so I am finding it hard to understand what changed in the upgrade.

shared.bedscannerSocket.createGlobalSocket()
msg = 'SCAN ' + str(rackType)+ ' text  '
s = shared.bedscannerSocket.getGlobal("_gSocket")
#time.sleep(.1)
data = shared.bedscannerSocket.getResp(s)
#time.sleep(.1)
data = shared.bedscannerSocket.sendMsgWResp(msg, s)
#time.sleep(.1)
data = shared.bedscannerSocket.getResp(s)
shared.bedscannerSocket.closeGlobalSocket()

Here is the shared folder.

################################################################################
#
#	These scripts are strictly for command/monitor of the Bedscanner on Port 8888
#
################################################################################

#Define the Dictionary
varGlobal= {}

#Set value in Dictionary /w reference key
def setGlobal(key, value):
	varGlobal[key]= value

#Get value in Dictionary /w reference key
def getGlobal(key):
	try:
		return varGlobal[key]
	except:
		return None

#Create the socket object globaly
def createGlobalSocket(): #add in a robot variable here to utilize multiple robots
	import socket
	
	host= "192.161.1.51"
	port= 8888
	
	s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((host,port))	
	varGlobal["_gSocket"]= s

#Send message to the socket object
def sendMsg(msg, socket):
	msg += "\r\n"
	socket.send(msg)

#Send message to the socket object, return the response
def sendMsgWResp(msg, socket):
	import time
	msg += "\r\n"
	socket.send(msg)
	time.sleep(.1)
	receivedMsg = socket.recv(4096)
	return receivedMsg
	
#Get the socket response
def getResp(socket):
	receivedMsg = socket.recv(4096)
	return receivedMsg

#Close the Socket object
def closeGlobalSocket(): #could add robot name here to close individual robot sockets
	s= varGlobal["_gSocket"]
	ret = sendMsgWResp("CLOSE", s)
	s.close()

Any input is greatly appreciated.

You may need to chunk/send the output yourself: Jython socket.send large sends - #8 by Kevin.Herron

Or better, and probably not what you want to hear, rewrite it to use Java sockets instead. The Jython socket library is poorly implemented.

Oops, I may have jumped the gun on that, your response is what’s short?

A good place to start might be comparing a Wireshark capture from 7.9 and 8.1 just to make sure nothing is funny there, but I’d still recommend avoiding Jython’s socket library if possible.

1 Like

I’m not familiar with Java; are there readily available examples out there?

I am requesting 4096 bytes but only getting 503 back.

Can you get a Wireshark capture that confirms there is a 4096 byte response but your script only sees 503?

Yea, possibly. I’m not super familiar with wireshark. This was the java code I was working on. I need help with the middle 3 lines to get a proper response when I send a command.

Command: ‘VERSION\r\n’
Response: up to 4096 bytes (more than 503)

from java.net import Socket, InetSocketAddress
from java.io import DataOutputStream

def get_data(cmd, ip):
	
	port = 8888

	try:
		s = Socket()
		s.connect(InetSocketAddress(ip, port), 2000)
		
		#outPrinter = DataOutputStream(s.getOutputStream())
		#outPrinter.write(cmd)
		#outPrinter.close()
		
		s.close()
		
		return True
	except IOError:
		return False
		
val = get_data('VERSION\r\n', '192.168.1.51')
print(val)

According to their copyright I can post this here. Ziath made this Python code to interface with their scanner. Probably useful for someone else who needs to open a socket and wait for a message. I implemented the code and had the system working in 5 minutes.

import socket
import time

"""This class demonstrates calling DataPaq to trigger a scan and 
retrieve the data from the server.  To run this code start DataPaq in server  
mode and generate a plate group with the class id of 1, then close DataPaq 
and run the server by executing server -s in the DataPaq program files (x86) 
directory to run the server.  Note that you can automate this by starting the 
process from Python.

This code may be freely distributed and modified, no warranty is given on 
this code.

Author : Neil Benn
Copyright : Ziath 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
"""
 
class DataPaqRemote:
    
    def __init__(self):
        "basic constructor"
        self.__readBuffer = ""
        self.__s = None
        self.__fs = None
        self.__connected = False
        
    def initialise(self):
        """Create a socket and connects it to DataPaq.  Ensure the firewall
        allows port 888 to connect to the localhost"""
        if self.__connected:
            raise Exception("Scanner already connected")        
        self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__s.connect(("localhost", 8888))
        self.__fs = self.__s.makefile()
        self.__fs.readline()
        self.__connected = True
        
    def disconnect(self):
        """Closes the socket and sets socket objects to None"""
        if not self.__connected:
            raise Exception("Scanner not connected")        
        self.__fs.close()
        self.__s.close()
        self.__fs = None
        self.__s = None
        self.__connected = False
        
    def getVersion(self):
        """Returns the version of the DataPaq Server"""
        if not self.__connected:
            raise Exception("Scanner not connected")
        self.__s.sendall("VERSION\r\n")
        version = self.__fs.readline()
        self.__fs.readline()
        return version.strip()
    
    def getStatus(self):
        """Returns the status of the DataPaq Server"""
        if not self.__connected:
            raise Exception("Scanner not connected")
        self.__s.sendall('STATUS\r\n')
        status = self.__fs.readline()
        self.__fs.readline()
        return status.strip()
        
    def scanRack(self, uid):
        """Triggers a scan and returns the scan data"""
        if not self.__connected:
            raise Exception("Scanner not connected")        
        self.__s.sendall('SCAN ' + uid + ' XML\r\n')
        scanFirstLine = True
        read_string = ''
        while True:
            line = self.__fs.readline()
            if scanFirstLine:
                if line.startswith('ERR'):
                    raise Exception('Scanner reported error ' +
                               adm     line + self.__readLine())
                scanFirstLine = False
            else:
                if line.startswith('OK'):
                    break
            if line.strip() != "":
                read_string += line
        return read_string
    
if __name__ == '__main__':
    """Executes a series of queries and returns the data from the DataPaq 
    Server"""
    print 'starting'
    dpr = DataPaqRemote()
    dpr.initialise()
    print 'Version = ' + dpr.getVersion()
    print 'Status = ' + dpr.getStatus()
    print 'Calling scan'
    scan_data = dpr.scanRack('1')
    print 'called scan'
    for line in scan_data.split('\r\n'):
        print line.strip()
    dpr.disconnect()
    print 'disconnected'
1 Like

Periodically we are getting the following error:

(<class '_socket.error'>, error(10054, 'Socket closed'), <traceback object at 0x7>)

when the following gets called

 def scanRack(self, uid):
        """Triggers a scan and returns the scan data"""
        if not self.__connected:
            raise Exception("Scanner not connected")        
        self.__s.sendall('SCAN ' + uid + ' text\r\n')
        scanFirstLine = True
        read_string = ''
        while True:
            line = self.__fs.readline()
            if scanFirstLine:
                if line.startswith('ERR'):
                    raise Exception('Scanner reported error ' +
                                    line + self.__readLine())
                scanFirstLine = False
            else:
                if line.startswith('OK'):
                    break
            if line.strip() != "":
                read_string += line
        return read_string

How would I get more information from this? The problem occurs in 1/60 calls or so.