I am trying to perform some remote audio processing with a NAO v4 using the version 2.1.4.13 of the python naoqi SDK, and I am having difficulties doing so. I have tried using the solution provided by Alexandre Mazel at NAO robot remote audio problems, but I am still having issues retrieving audio data from the buffer. The code referenced in the post is available below. I have also followed the instructions for remotely processing audio data found at https://www.generationrobots.com/media/NAO%20Next%20Gen/FeaturePaper(AudioSignalProcessing)%20(1).pdf
I would greatly appreciate any help or solutions, as I have been stuck on this problem for several days now.
# -*- coding: utf-8 -*-
###########################################################
# Retrieve robot audio buffer
# Syntaxe:
# python scriptname --pip <ip> --pport <port>
#
# --pip <ip>: specify the ip of your robot (without specification it will use the NAO_IP defined some line below
#
# Author: Alexandre Mazel
###########################################################
NAO_IP = "10.0.252.126" # Romeo on table
#~ NAO_IP = "10.0.253.99" # Nao Alex Blue
from optparse import OptionParser
import naoqi
import numpy as np
import time
import sys
class SoundReceiverModule(naoqi.ALModule):
"""
Use this object to get call back from the ALMemory of the naoqi world.
Your callback needs to be a method with two parameter (variable name, value).
"""
def __init__( self, strModuleName, strNaoIp ):
try:
naoqi.ALModule.__init__(self, strModuleName );
self.BIND_PYTHON( self.getName(),"callback" );
self.strNaoIp = strNaoIp;
self.outfile = None;
self.aOutfile = [None]*(4-1); # ASSUME max nbr channels = 4
except BaseException, err:
print( "ERR: abcdk.naoqitools.SoundReceiverModule: loading error: %s" % str(err) );
# __init__ - end
def __del__( self ):
print( "INF: abcdk.SoundReceiverModule.__del__: cleaning everything" );
self.stop();
def start( self ):
audio = naoqi.ALProxy( "ALAudioDevice", self.strNaoIp, 9559 );
nNbrChannelFlag = 0; # ALL_Channels: 0, AL::LEFTCHANNEL: 1, AL::RIGHTCHANNEL: 2; AL::FRONTCHANNEL: 3 or AL::REARCHANNEL: 4.
nDeinterleave = 0;
nSampleRate = 48000;
audio.setClientPreferences( self.getName(), nSampleRate, nNbrChannelFlag, nDeinterleave ); # setting same as default generate a bug !?!
audio.subscribe( self.getName() );
print( "INF: SoundReceiver: started!" );
# self.processRemote( 4, 128, [18,0], "A"*128*4*2 ); # for local test
# on romeo, here's the current order:
# 0: right; 1: rear; 2: left; 3: front,
def stop( self ):
print( "INF: SoundReceiver: stopping..." );
audio = naoqi.ALProxy( "ALAudioDevice", self.strNaoIp, 9559 );
audio.unsubscribe( self.getName() );
print( "INF: SoundReceiver: stopped!" );
if( self.outfile != None ):
self.outfile.close();
def processRemote( self, nbOfChannels, nbrOfSamplesByChannel, aTimeStamp, buffer ):
"""
This is THE method that receives all the sound buffers from the "ALAudioDevice" module
"""
#~ print( "process!" );
#~ print( "processRemote: %s, %s, %s, lendata: %s, data0: %s (0x%x), data1: %s (0x%x)" % (nbOfChannels, nbrOfSamplesByChannel, aTimeStamp, len(buffer), buffer[0],ord(buffer[0]),buffer[1],ord(buffer[1])) );
#~ print( "raw data: " ),
#~ for i in range( 8 ):
#~ print( "%s (0x%x), " % (buffer[i],ord(buffer[i])) ),
#~ print( "" );
aSoundDataInterlaced = np.fromstring( str(buffer), dtype=np.int16 );
#~ print( "len data: %s " % len( aSoundDataInterlaced ) );
#~ print( "data interlaced: " ),
#~ for i in range( 8 ):
#~ print( "%d, " % (aSoundDataInterlaced[i]) ),
#~ print( "" );
aSoundData = np.reshape( aSoundDataInterlaced, (nbOfChannels, nbrOfSamplesByChannel), 'F' );
#~ print( "len data: %s " % len( aSoundData ) );
#~ print( "len data 0: %s " % len( aSoundData[0] ) );
if( False ):
# compute average
aAvgValue = np.mean( aSoundData, axis = 1 );
print( "avg: %s" % aAvgValue );
if( False ):
# compute fft
nBlockSize = nbrOfSamplesByChannel;
signal = aSoundData[0] * np.hanning( nBlockSize );
aFft = ( np.fft.rfft(signal) / nBlockSize );
print aFft;
if( False ):
# compute peak
aPeakValue = np.max( aSoundData );
if( aPeakValue > 16000 ):
print( "Peak: %s" % aPeakValue );
if( True ):
bSaveAll = True;
# save to file
if( self.outfile == None ):
strFilenameOut = "/out.raw";
print( "INF: Writing sound to '%s'" % strFilenameOut );
self.outfile = open( strFilenameOut, "wb" );
if( bSaveAll ):
for nNumChannel in range( 1, nbOfChannels ):
strFilenameOutChan = strFilenameOut.replace(".raw", "_%d.raw"%nNumChannel);
self.aOutfile[nNumChannel-1] = open( strFilenameOutChan, "wb" );
print( "INF: Writing other channel sound to '%s'" % strFilenameOutChan );
#~ aSoundDataInterlaced.tofile( self.outfile ); # wrote the 4 channels
aSoundData[0].tofile( self.outfile ); # wrote only one channel
#~ print( "aTimeStamp: %s" % aTimeStamp );
#~ print( "data wrotten: " ),
#~ for i in range( 8 ):
#~ print( "%d, " % (aSoundData[0][i]) ),
#~ print( "" );
#~ self.stop(); # make naoqi crashes
if( bSaveAll ):
for nNumChannel in range( 1, nbOfChannels ):
aSoundData[nNumChannel].tofile( self.aOutfile[nNumChannel-1] );
# processRemote - end
def version( self ):
return "0.6";
# SoundReceiver - end
def main():
""" Main entry point
"""
parser = OptionParser()
parser.add_option("--pip",
help="Parent broker port. The IP address or your robot",
dest="pip")
parser.add_option("--pport",
help="Parent broker port. The port NAOqi is listening to",
dest="pport",
type="int")
parser.set_defaults(
pip=NAO_IP,
pport=9559)
(opts, args_) = parser.parse_args()
pip = opts.pip
pport = opts.pport
# We need this broker to be able to construct
# NAOqi modules and subscribe to other modules
# The broker must stay alive until the program exists
myBroker = naoqi.ALBroker("myBroker",
"0.0.0.0", # listen to anyone
0, # find a free port and use it
pip, # parent broker IP
pport) # parent broker port
# Warning: SoundReceiver must be a global variable
# The name given to the constructor must be the name of the
# variable
global SoundReceiver
SoundReceiver = SoundReceiverModule("SoundReceiver", pip)
SoundReceiver.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print
print "Interrupted by user, shutting down"
myBroker.shutdown()
sys.exit(0)
if __name__ == "__main__":
main()
Maybe this project can help you as orientation:
https://github.com/UNSWComputing/rUNSWift-2015-release/wiki/Whistle-Detection
It offers a whistle_detector.py Python module that
also runs on the Nao under the 2.1 toolchain / Nao V4.
Also this project is worth a visit:
https://www.ibm.com/blogs/watson/2016/07/getting-robots-listen-using-watsons-speech-text-service/
It uses an approach by calling the linux command arecord instead of using ALAudioDevice
Have you tried the example from the documentation?
Try to run this on the robot:
#! /usr/bin/env python
# -*- encoding: UTF-8 -*-
"""Example: Get Signal from Front Microphone & Calculate its rms Power"""
import qi
import argparse
import sys
import time
import numpy as np
class SoundProcessingModule(object):
"""
A simple get signal from the front microphone of Nao & calculate its rms power.
It requires numpy.
"""
def __init__( self, app):
"""
Initialise services and variables.
"""
super(SoundProcessingModule, self).__init__()
app.start()
session = app.session
# Get the service ALAudioDevice.
self.audio_service = session.service("ALAudioDevice")
self.isProcessingDone = False
self.nbOfFramesToProcess = 20
self.framesCount=0
self.micFront = []
self.module_name = "SoundProcessingModule"
def startProcessing(self):
"""
Start processing
"""
# ask for the front microphone signal sampled at 16kHz
# if you want the 4 channels call setClientPreferences(self.module_name, 48000, 0, 0)
self.audio_service.setClientPreferences(self.module_name, 16000, 3, 0)
self.audio_service.subscribe(self.module_name)
while self.isProcessingDone == False:
time.sleep(1)
self.audio_service.unsubscribe(self.module_name)
def processRemote(self, nbOfChannels, nbOfSamplesByChannel, timeStamp, inputBuffer):
"""
Compute RMS from mic.
"""
self.framesCount = self.framesCount + 1
if (self.framesCount <= self.nbOfFramesToProcess):
# convert inputBuffer to signed integer as it is interpreted as a string by python
self.micFront=self.convertStr2SignedInt(inputBuffer)
#compute the rms level on front mic
rmsMicFront = self.calcRMSLevel(self.micFront)
print "rms level mic front = " + str(rmsMicFront)
else :
self.isProcessingDone=True
def calcRMSLevel(self,data) :
"""
Calculate RMS level
"""
rms = 20 * np.log10( np.sqrt( np.sum( np.power(data,2) / len(data) )))
return rms
def convertStr2SignedInt(self, data) :
"""
This function takes a string containing 16 bits little endian sound
samples as input and returns a vector containing the 16 bits sound
samples values converted between -1 and 1.
"""
signedData=[]
ind=0;
for i in range (0,len(data)/2) :
signedData.append(data[ind]+data[ind+1]*256)
ind=ind+2
for i in range (0,len(signedData)) :
if signedData[i]>=32768 :
signedData[i]=signedData[i]-65536
for i in range (0,len(signedData)) :
signedData[i]=signedData[i]/32768.0
return signedData
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip", type=str, default="127.0.0.1",
help="Robot IP address. On robot or Local Naoqi: use '127.0.0.1'.")
parser.add_argument("--port", type=int, default=9559,
help="Naoqi port number")
args = parser.parse_args()
try:
# Initialize qi framework.
connection_url = "tcp://" + args.ip + ":" + str(args.port)
app = qi.Application(["SoundProcessingModule", "--qi-url=" + connection_url])
except RuntimeError:
print ("Can't connect to Naoqi at ip \"" + args.ip + "\" on port " + str(args.port) +".\n"
"Please check your script arguments. Run with -h option for help.")
sys.exit(1)
MySoundProcessingModule = SoundProcessingModule(app)
app.session.registerService("SoundProcessingModule", MySoundProcessingModule)
MySoundProcessingModule.startProcessing()
Related
Im having a problem with using telenetlib in python 3. Here is my code:
import time
import os
originalTime=0
state=0
def cleanString(inText):
inText = inText.rstrip()
params, inText = inText.split("=",1)
inText = str(inText)
return inText
def notify(title, text, sound):
os.system("""osascript -e 'display notification "{}" with title "{}" sound name "{}"'
""".format(text, title, sound))
def shutdown():
os.system("""osascript -e 'tell application "System Events"
shut down
end tell'
""")
dataFile = open("NUT.conf", "r")
login = cleanString(dataFile.readline())
password = cleanString(dataFile.readline())
host = cleanString(dataFile.readline())
port = cleanString(dataFile.readline())
upsName = cleanString(dataFile.readline())
shutdownTime = cleanString(dataFile.readline())
shutdownTime = shutdownTime*60,000
print(login)
print(password)
print(host)
print(port)
print(upsName)
print(shutdownTime)
ups_handler=PyNUT.PyNUTClient(host=host, port=port, login=login, password=password)
upsInfo = ups_handler.GetUPSVars(upsName)
while True:
upsInfo = ups_handler.GetUPSVars(upsName)
if upsInfo['ups.status']=='OB DISCHRG' and state!=1:
originalTime = time.time()
state=1
elif upsInfo['ups.status']=='OB DISCHRG' :
print("PANIC")
if(int(originalTime)+int( shutdownTime))==time.time():
notify("UPS Alert", "Detected UPS power loss. Shutting down NAS in "+shutdownTime+" minute(s).", "Funk")
#TODO shutdown computer
if upsInfo['ups.status']=='OL':
state=0
Here is the pyNUT library:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2008 David Goncalves <david#lestat.st>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# 2008-01-14 David Goncalves
# PyNUT is an abstraction class to access NUT (Network UPS Tools) server.
#
# 2008-06-09 David Goncalves
# Added 'GetRWVars' and 'SetRWVar' commands.
#
# 2009-02-19 David Goncalves
# Changed class PyNUT to PyNUTClient
#
# 2010-07-23 David Goncalves - Version 1.2
# Changed GetRWVars function that fails is the UPS is not
# providing such vars.
#
# 2011-07-05 René Martín Rodríguez <rmrodri#ull.es> - Version 1.2.1
# Added support for FSD, HELP and VER commands
#
# 2012-02-07 René Martín Rodríguez <rmrodri#ull.es> - Version 1.2.2
# Added support for LIST CLIENTS command
#
# 2014-06-03 george2 - Version 1.3.0
# Added custom exception class, fixed minor bug, added Python 3 support.
#
import telnetlib
class PyNUTError(Exception):
""" Base class for custom exceptions """
class PyNUTClient:
""" Abstraction class to access NUT (Network UPS Tools) server """
__debug = None # Set class to debug mode (prints everything useful for debugging...)
__host = None
__port = None
__login = None
__password = None
__timeout = None
__srv_handler = None
__version = "1.3.0"
__release = "2014-06-03"
def __init__( self, host="127.0.0.1", port=3493, login=None, password=None, debug=False, timeout=5 ) :
""" Class initialization method
host : Host to connect (default to localhost)
port : Port where NUT listens for connections (default to 3493)
login : Login used to connect to NUT server (default to None for no authentication)
password : Password used when using authentication (default to None)
debug : Boolean, put class in debug mode (prints everything on console, default to False)
timeout : Timeout used to wait for network response
"""
self.__debug = debug
if self.__debug :
print( "[DEBUG] Class initialization..." )
print( "[DEBUG] -> Host = %s (port %s)" % ( host, port ) )
print( "[DEBUG] -> Login = '%s' / '%s'" % ( login, password ) )
self.__host = host
self.__port = port
self.__login = login
self.__password = password
self.__timeout = 5
self.__connect()
# Try to disconnect cleanly when class is deleted ;)
def __del__( self ) :
""" Class destructor method """
try :
self.__srv_handler.write( "LOGOUT\n" )
except :
pass
def __connect( self ) :
""" Connects to the defined server
If login/pass was specified, the class tries to authenticate. An error is raised
if something goes wrong.
"""
if self.__debug :
print( "[DEBUG] Connecting to host" )
self.__srv_handler = telnetlib.Telnet( self.__host, self.__port )
if self.__login != None :
self.__srv_handler.write( "USERNAME %s\n" % self.__login )
result = self.__srv_handler.read_until( "\n", self.__timeout )
if result[:2] != "OK" :
raise PyNUTError( result.replace( "\n", "" ) )
if self.__password != None :
self.__srv_handler.write( "PASSWORD %s\n" % self.__password )
result = self.__srv_handler.read_until( "\n", self.__timeout )
if result[:2] != "OK" :
raise PyNUTError( result.replace( "\n", "" ) )
def GetUPSList( self ) :
""" Returns the list of available UPS from the NUT server
The result is a dictionary containing 'key->val' pairs of 'UPSName' and 'UPS Description'
"""
if self.__debug :
print( "[DEBUG] GetUPSList from server" )
self.__srv_handler.write( "LIST UPS\n" )
result = self.__srv_handler.read_until( "\n" )
if result != "BEGIN LIST UPS\n" :
raise PyNUTError( result.replace( "\n", "" ) )
result = self.__srv_handler.read_until( "END LIST UPS\n" )
ups_list = {}
for line in result.split( "\n" ) :
if line[:3] == "UPS" :
ups, desc = line[4:-1].split( '"' )
ups_list[ ups.replace( " ", "" ) ] = desc
return( ups_list )
def GetUPSVars( self, ups="" ) :
""" Get all available vars from the specified UPS
The result is a dictionary containing 'key->val' pairs of all
available vars.
"""
if self.__debug :
print( "[DEBUG] GetUPSVars called..." )
self.__srv_handler.write( "LIST VAR %s\n" % ups )
result = self.__srv_handler.read_until( "\n" )
if result != "BEGIN LIST VAR %s\n" % ups :
raise PyNUTError( result.replace( "\n", "" ) )
ups_vars = {}
result = self.__srv_handler.read_until( "END LIST VAR %s\n" % ups )
offset = len( "VAR %s " % ups )
end_offset = 0 - ( len( "END LIST VAR %s\n" % ups ) + 1 )
for current in result[:end_offset].split( "\n" ) :
var = current[ offset: ].split( '"' )[0].replace( " ", "" )
data = current[ offset: ].split( '"' )[1]
ups_vars[ var ] = data
return( ups_vars )
def GetUPSCommands( self, ups="" ) :
""" Get all available commands for the specified UPS
The result is a dict object with command name as key and a description
of the command as value
"""
if self.__debug :
print( "[DEBUG] GetUPSCommands called..." )
self.__srv_handler.write( "LIST CMD %s\n" % ups )
result = self.__srv_handler.read_until( "\n" )
if result != "BEGIN LIST CMD %s\n" % ups :
raise PyNUTError( result.replace( "\n", "" ) )
ups_cmds = {}
result = self.__srv_handler.read_until( "END LIST CMD %s\n" % ups )
offset = len( "CMD %s " % ups )
end_offset = 0 - ( len( "END LIST CMD %s\n" % ups ) + 1 )
for current in result[:end_offset].split( "\n" ) :
var = current[ offset: ].split( '"' )[0].replace( " ", "" )
# For each var we try to get the available description
try :
self.__srv_handler.write( "GET CMDDESC %s %s\n" % ( ups, var ) )
temp = self.__srv_handler.read_until( "\n" )
if temp[:7] != "CMDDESC" :
raise PyNUTError
else :
off = len( "CMDDESC %s %s " % ( ups, var ) )
desc = temp[off:-1].split('"')[1]
except :
desc = var
ups_cmds[ var ] = desc
return( ups_cmds )
def GetRWVars( self, ups="" ) :
""" Get a list of all writable vars from the selected UPS
The result is presented as a dictionary containing 'key->val' pairs
"""
if self.__debug :
print( "[DEBUG] GetUPSVars from '%s'..." % ups )
self.__srv_handler.write( "LIST RW %s\n" % ups )
result = self.__srv_handler.read_until( "\n" )
if ( result != "BEGIN LIST RW %s\n" % ups ) :
raise PyNUTError( result.replace( "\n", "" ) )
result = self.__srv_handler.read_until( "END LIST RW %s\n" % ups )
offset = len( "VAR %s" % ups )
end_offset = 0 - ( len( "END LIST RW %s\n" % ups ) + 1 )
rw_vars = {}
try :
for current in result[:end_offset].split( "\n" ) :
var = current[ offset: ].split( '"' )[0].replace( " ", "" )
data = current[ offset: ].split( '"' )[1]
rw_vars[ var ] = data
except :
pass
return( rw_vars )
def SetRWVar( self, ups="", var="", value="" ):
""" Set a variable to the specified value on selected UPS
The variable must be a writable value (cf GetRWVars) and you must have the proper
rights to set it (maybe login/password).
"""
self.__srv_handler.write( "SET VAR %s %s %s\n" % ( ups, var, value ) )
result = self.__srv_handler.read_until( "\n" )
if ( result == "OK\n" ) :
return( "OK" )
else :
raise PyNUTError( result )
def RunUPSCommand( self, ups="", command="" ) :
""" Send a command to the specified UPS
Returns OK on success or raises an error
"""
if self.__debug :
print( "[DEBUG] RunUPSCommand called..." )
self.__srv_handler.write( "INSTCMD %s %s\n" % ( ups, command ) )
result = self.__srv_handler.read_until( "\n" )
if ( result == "OK\n" ) :
return( "OK" )
else :
raise PyNUTError( result.replace( "\n", "" ) )
def FSD( self, ups="") :
""" Send FSD command
Returns OK on success or raises an error
"""
if self.__debug :
print( "[DEBUG] MASTER called..." )
self.__srv_handler.write( "MASTER %s\n" % ups )
result = self.__srv_handler.read_until( "\n" )
if ( result != "OK MASTER-GRANTED\n" ) :
raise PyNUTError( ( "Master level function are not available", "" ) )
if self.__debug :
print( "[DEBUG] FSD called..." )
self.__srv_handler.write( "FSD %s\n" % ups )
result = self.__srv_handler.read_until( "\n" )
if ( result == "OK FSD-SET\n" ) :
return( "OK" )
else :
raise PyNUTError( result.replace( "\n", "" ) )
def help(self) :
""" Send HELP command
"""
if self.__debug :
print( "[DEBUG] HELP called..." )
self.__srv_handler.write( "HELP\n")
return self.__srv_handler.read_until( "\n" )
def ver(self) :
""" Send VER command
"""
if self.__debug :
print( "[DEBUG] VER called..." )
self.__srv_handler.write( "VER\n")
return self.__srv_handler.read_until( "\n" )
def ListClients( self, ups = None ) :
""" Returns the list of connected clients from the NUT server
The result is a dictionary containing 'key->val' pairs of 'UPSName' and a list of clients
"""
if self.__debug :
print( "[DEBUG] ListClients from server" )
if ups and (ups not in self.GetUPSList()):
raise PyNUTError( "%s is not a valid UPS" % ups )
if ups:
self.__srv_handler.write( "LIST CLIENTS %s\n" % ups)
else:
self.__srv_handler.write( "LIST CLIENTS\n" )
result = self.__srv_handler.read_until( "\n" )
if result != "BEGIN LIST CLIENTS\n" :
raise PyNUTError( result.replace( "\n", "" ) )
result = self.__srv_handler.read_until( "END LIST CLIENTS\n" )
ups_list = {}
for line in result.split( "\n" ):
if line[:6] == "CLIENT" :
host, ups = line[7:].split(' ')
ups.replace(' ', '')
if not ups in ups_list:
ups_list[ups] = []
ups_list[ups].append(host)
return( ups_list )
It is throwing me this error:
Traceback (most recent call last):
File "/Users/gabrielcsizmadia/Documents/GitHub/nut-shutdown-app/main.py", line 43, in <module>
ups_handler=PyNUT.PyNUTClient(host=host, port=port, login=login, password=password)
File "/Users/gabrielcsizmadia/Documents/GitHub/nut-shutdown-app/PyNUT.py", line 86, in __init__
self.__connect()
File "/Users/gabrielcsizmadia/Documents/GitHub/nut-shutdown-app/PyNUT.py", line 108, in __connect
self.__srv_handler.write( "USERNAME %s\n" % self.__login )
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/telnetlib.py", line 287, in write
if IAC in buffer:
TypeError: 'in <string>' requires string as left operand, not bytes
File "/Users/gabrielcsizmadia/Desktop/Homelab/NUT Shutdown/MacOS Shutdown/PyNUT.py", line 108, in __connect
self.__srv_handler.write( "USERNAME %s\n" % self.__login )
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/telnetlib.py", line 287, in write
if IAC in buffer:
TypeError: 'in <string>' requires string as left operand, not bytes
Not sure where to go from here...
Any help would be much appreciated!
EDIT: I have updated the error, I posted the wrong error in the original code... I have also added more to the code.
I also noticed that it runs fine in Python 2.7 but not Python 3. This might help someone.
The problem is that pyNUT is written for Python 2. telnetlib expects most of its inputs to be bytes. In Python 2 the str type was a bytestring, but in Python 3 it's unicode.
The pyNUT code is using string literals to format strings internally, like this:
self.__srv_handler.write( "USERNAME %s\n" % self.__login )
so passing bytes isn't going to help:
>>> 'Hello %s' % 'world'.encode('ascii')
"Hello b'world'"
pyNUT needs to be modified to pass bytes to telnetlib. For example
self.__srv_handler.write( b"USERNAME %s\n" % self.__login.encode('ascii') )
Try
print(objName.Hello().decode('utf-8'))
It seems there is not very much support for what I am trying to do, but it is supposed to be possible since it is demonstrated in temperature sensor and sensor filter tutorial. However, there are no examples for the actual message creation from an edge module in python. That tutorial only shows forwarding messages. There are examples of sending from a device, but devices use a different class than edge modules. From the filter example and from a couple of device examples I have pieced together the following:
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.
import random
import time
import sys
import iothub_client
from iothub_client import IoTHubModuleClient, IoTHubClientError, IoTHubTransportProvider
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError
# messageTimeout - the maximum time in milliseconds until a message times out.
# The timeout period starts at IoTHubModuleClient.send_event_async.
# By default, messages do not expire.
MESSAGE_TIMEOUT = 10000
# global counters
RECEIVE_CALLBACKS = 0
SEND_CALLBACKS = 0
# Choose HTTP, AMQP or MQTT as transport protocol. Currently only MQTT is supported.
PROTOCOL = IoTHubTransportProvider.MQTT
# Callback received when the message that we're forwarding is processed.
def send_confirmation_callback(message, result, user_context):
global SEND_CALLBACKS
print ( "Confirmation[%d] received for message with result = %s" % (user_context, result) )
map_properties = message.properties()
key_value_pair = map_properties.get_internals()
print ( " Properties: %s" % key_value_pair )
SEND_CALLBACKS += 1
print ( " Total calls confirmed: %d" % SEND_CALLBACKS )
# receive_message_callback is invoked when an incoming message arrives on the specified
# input queue (in the case of this sample, "input1"). Because this is a filter module,
# we will forward this message onto the "output1" queue.
def receive_message_callback(message, hubManager):
global RECEIVE_CALLBACKS
message_buffer = message.get_bytearray()
size = len(message_buffer)
print ( " Data: <<<%s>>> & Size=%d" % (message_buffer[:size].decode('utf-8'), size) )
map_properties = message.properties()
key_value_pair = map_properties.get_internals()
print ( " Properties: %s" % key_value_pair )
RECEIVE_CALLBACKS += 1
print ( " Total calls received: %d" % RECEIVE_CALLBACKS )
hubManager.forward_event_to_output("output1", message, 0)
return IoTHubMessageDispositionResult.ACCEPTED
def construct_message(message_body, topic):
try:
msg_txt_formatted = message_body
message = IoTHubMessage(msg_txt_formatted)
# Add a custom application property to the message.
# An IoT hub can filter on these properties without access to the message body.
prop_map = message.properties()
prop_map.add("topic", topic)
# TODO Use logging
# Send the message.
print( "Sending message: %s" % message.get_string() )
except IoTHubError as iothub_error:
print ( "Unexpected error %s from IoTHub" % iothub_error )
return
return message
class HubManager(object):
def __init__(
self,
protocol=IoTHubTransportProvider.MQTT):
self.client_protocol = protocol
self.client = IoTHubModuleClient()
self.client.create_from_environment(protocol)
# set the time until a message times out
self.client.set_option("messageTimeout", MESSAGE_TIMEOUT)
# sets the callback when a message arrives on "input1" queue. Messages sent to
# other inputs or to the default will be silently discarded.
self.client.set_message_callback("input1", receive_message_callback, self)
# Forwards the message received onto the next stage in the process.
def forward_event_to_output(self, outputQueueName, event, send_context):
self.client.send_event_async(
outputQueueName, event, send_confirmation_callback, send_context)
def send_message(self, message):
# No callback
# TODO what is the third arg?
self.client.send_event_async(
"output1", message, send_confirmation_callback, 0)
self.client.send_message()
def mypublish(self, topic, msg):
message = construct_message(msg, topic)
self.send_message(message)
print('publishing %s', msg)
def main(protocol):
try:
print ( "\nPython %s\n" % sys.version )
print ( "IoT Hub Client for Python" )
hub_manager = HubManager(protocol)
print ( "Starting the IoT Hub Python sample using protocol %s..." % hub_manager.client_protocol )
print ( "The sample is now waiting for messages and will indefinitely. Press Ctrl-C to exit. ")
while True:
hub_manager.mypublish('testtopic', 'hello world this is a module')
time.sleep(1)
except IoTHubError as iothub_error:
print ( "Unexpected error %s from IoTHub" % iothub_error )
return
except KeyboardInterrupt:
print ( "IoTHubModuleClient sample stopped" )
if __name__ == '__main__':
main(PROTOCOL)
When I build and deploy this it executes on the edge device without errors and in the log, the callback reports that the messages are sent ok. However, no messages come through when I attempt to monitor D2C messages.
I used this to create and send a message from a JSON dict.
new_message = json.dumps(json_obj)
new_message = IoTHubMessage(new_message)
hubManager.forward_event_to_output("output1", new_message, 0)
You can send anything you need, even strings or whatever.
To narrow down the issue, you can install the azureiotedge-simulated-temperature-sensor module published by Microsoft to see whether the issue relative to the Edge environment issue or coding.
I also wrote a sample Python code module based on the Python Module templates which works well for me, you can refer the code below:
# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for
# full license information.
import random
import time
import sys
import iothub_client
from iothub_client import IoTHubModuleClient, IoTHubClientError, IoTHubTransportProvider
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError
# messageTimeout - the maximum time in milliseconds until a message times out.
# The timeout period starts at IoTHubModuleClient.send_event_async.
# By default, messages do not expire.
MESSAGE_TIMEOUT = 10000
# global counters
RECEIVE_CALLBACKS = 0
SEND_CALLBACKS = 0
# Choose HTTP, AMQP or MQTT as transport protocol. Currently only MQTT is supported.
PROTOCOL = IoTHubTransportProvider.MQTT
# Callback received when the message that we're forwarding is processed.
def send_confirmation_callback(message, result, user_context):
global SEND_CALLBACKS
print ( "Confirmation[%d] received for message with result = %s" % (user_context, result) )
map_properties = message.properties()
key_value_pair = map_properties.get_internals()
print ( " Properties: %s" % key_value_pair )
SEND_CALLBACKS += 1
print ( " Total calls confirmed: %d" % SEND_CALLBACKS )
# receive_message_callback is invoked when an incoming message arrives on the specified
# input queue (in the case of this sample, "input1"). Because this is a filter module,
# we will forward this message onto the "output1" queue.
def receive_message_callback(message, hubManager):
global RECEIVE_CALLBACKS
message_buffer = message.get_bytearray()
size = len(message_buffer)
print ( " Data: <<<%s>>> & Size=%d" % (message_buffer[:size].decode('utf-8'), size) )
map_properties = message.properties()
key_value_pair = map_properties.get_internals()
print ( " Properties: %s" % key_value_pair )
RECEIVE_CALLBACKS += 1
print ( " Total calls received: %d" % RECEIVE_CALLBACKS )
hubManager.forward_event_to_output("output1", message, 0)
return IoTHubMessageDispositionResult.ACCEPTED
class HubManager(object):
def __init__(
self,
protocol=IoTHubTransportProvider.MQTT):
self.client_protocol = protocol
self.client = IoTHubModuleClient()
self.client.create_from_environment(protocol)
# set the time until a message times out
self.client.set_option("messageTimeout", MESSAGE_TIMEOUT)
# sets the callback when a message arrives on "input1" queue. Messages sent to
# other inputs or to the default will be silently discarded.
self.client.set_message_callback("input1", receive_message_callback, self)
# Forwards the message received onto the next stage in the process.
def forward_event_to_output(self, outputQueueName, event, send_context):
self.client.send_event_async(
outputQueueName, event, send_confirmation_callback, send_context)
def SendSimulationData(self, msg):
print"sending message..."
message=IoTHubMessage(msg)
self.client.send_event_async(
"output1", message, send_confirmation_callback, 0)
print"finished sending message..."
def main(protocol):
try:
print ( "\nPython %s\n" % sys.version )
print ( "IoT Hub Client for Python" )
hub_manager = HubManager(protocol)
print ( "Starting the IoT Hub Python sample using protocol %s..." % hub_manager.client_protocol )
print ( "The sample is now waiting for messages and will indefinitely. Press Ctrl-C to exit. ")
while True:
hub_manager.SendSimulationData("test msg")
time.sleep(1)
except IoTHubError as iothub_error:
print ( "Unexpected error %s from IoTHub" % iothub_error )
return
except KeyboardInterrupt:
print ( "IoTHubModuleClient sample stopped" )
if __name__ == '__main__':
main(PROTOCOL)
If it can help someone, I think you miss await send_message.
Seems the same problem I answered here
I'm looking to do something in this example: Python - How to get the start/base address of a process?. I'm having the same issue as the person in that topic, in that the pointers cheat engine provides is in reference to the base address of the process itself.
I've looked around and it looks like the best solution is to use ctypes and the MODULEENTRY32 to store snapshots of processes and analyze their modBaseAddr.
Here is my current code
import os.path, ctypes, ctypes.wintypes
from ctypes import *
from ctypes.wintypes import *
PROCESS_QUERY_INFORMATION = (0x0400)
PROCESS_VM_OPERATION = (0x0008)
PROCESS_VM_READ = (0x0010)
PROCESS_VM_WRITE = (0x0020)
TH32CS_SNAPMODULE = (0x00000008)
CreateToolhelp32Snapshot= ctypes.windll.kernel32.CreateToolhelp32Snapshot
Process32First = ctypes.windll.kernel32.Process32First
Process32Next = ctypes.windll.kernel32.Process32Next
Module32First = ctypes.windll.kernel32.Module32First
Module32Next = ctypes.windll.kernel32.Module32Next
GetLastError = ctypes.windll.kernel32.GetLastError
OpenProcess = ctypes.windll.kernel32.OpenProcess
GetPriorityClass = ctypes.windll.kernel32.GetPriorityClass
CloseHandle = ctypes.windll.kernel32.CloseHandle
class MODULEENTRY32(Structure):
_fields_ = [ ( 'dwSize' , DWORD ) ,
( 'th32ModuleID' , DWORD ),
( 'th32ProcessID' , DWORD ),
( 'GlblcntUsage' , DWORD ),
( 'ProccntUsage' , DWORD ) ,
( 'modBaseAddr' , POINTER(BYTE)) ,
( 'modBaseSize' , DWORD ) ,
( 'hModule' , HMODULE ) ,
( 'szModule' , c_char * 256 ),
( 'szExePath' , c_char * 260 ) ]
def GetBaseAddr(ProcId, ProcName):
me32 = MODULEENTRY32()
me32.dwSize = sizeof(me32)
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ProcId)
if GetLastError() != 0:
CloseHandle(hSnapshot)
print 'Handle Error %s' % WinError()
return 'Error'
else:
if Module32First(hSnapshot, byref(me32)):
if me32.szModule == ProcName:
CloseHandle(hSnapshot)
return id(me32.modBaseAddr)
else:
Module32Next(hSnapshot, byref(me32))
while int(GetLastError())!= 18:
if me32.szModule == ProcName:
CloseHandle(hSnapshot)
return id(me32.modBaseAddr)
else:
Module32Next(hSnapshot, byref(me32))
CloseHandle(hSnapshot)
print 'Couldn\'t find Process with name %s' % ProcName
else:
print 'Module32First is False %s' % WinError()
CloseHandle(hSnapshot)
def GetProcessIdByName( pName):
if pName.endswith('.exe'):
pass
else:
pName = pName+'.exe'
ProcessIds, BytesReturned = EnumProcesses()
for index in range(BytesReturned / ctypes.sizeof(ctypes.wintypes.DWORD)):
ProcessId = ProcessIds[index]
hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId)
if hProcess:
ImageFileName = (ctypes.c_char*MAX_PATH)()
if ctypes.windll.psapi.GetProcessImageFileNameA(hProcess, ImageFileName, MAX_PATH)>0:
filename = os.path.basename(ImageFileName.value)
if filename == pName:
return ProcessId
CloseHandle(hProcess)
def EnumProcesses():
count = 32
while True:
ProcessIds = (ctypes.wintypes.DWORD*count)()
cb = ctypes.sizeof(ProcessIds)
BytesReturned = ctypes.wintypes.DWORD()
if ctypes.windll.Psapi.EnumProcesses(ctypes.byref(ProcessIds), cb, ctypes.byref(BytesReturned)):
if BytesReturned.value<cb:
return ProcessIds, BytesReturned.value
break
else:
count *= 2
else:
return None
if __name__ == '__main__':
ProcId = GetProcessIdByName('RocketLeague.exe')
#print ProcId
print hex(GetBaseAddr(ProcId, 'RocketLeague.exe'))
#print hex(GetBaseAddr(8252,'RocketLeague.exe'))
Now my understanding of memory isn't the greatest, but I'd figure that the base address should be static while a program is running. When I do get this code to run, the ModBaseAddr I get back changes every time I run it. Another weird Issue I'm having is that without that print ProcId statement, running the program returns an ERROR_ACCESS_DENIED (error 5) from line 41 (This has something to do with the CreateToolhelp32Snapshot function I assume as I have admin rights on the computer). With the print statement, however, the program runs through giving me a different ModBaseAddr every time. If I feed the GetBaseAddr function the ProcessId manually it also works without the print statement, again however, it's giving me a random address every time.
If anyone could provide me any help or point me in the right direction I'd really appreciate it!
Clarification: MODULEENTRY32 stores information about modules, not processes. when you call CreateToolhelp32Snapshot using TH32CS_SNAPMODULE you are getting modules loaded by the process, not processes themselves.
Instead of getting the MODULEENTRY32 in combination with EnumProcesses you can instead use CreateToolHelp32Snapshot with TH32CS_SNAPPROCESS to get a list of processes in the form of PROCESSENRTY32 structs, which also contains the process identifier.
Despite being a user with administrator privileges, you must also run the process as an administrator.
You should also ensure you're initializing your MODULEENTRY32 to {0} for proper error handling and not running into an issue of the returned value being subject to undefined behavior of uninitialized memory.
I do not know the specific cause of your issue but I have used a source code for this purpose that is very robust that may be a plug and play alternative to what you're currently using, the important snippet will follow, but the full source is available here.
def ListProcessModules( ProcessID ):
hModuleSnap = c_void_p(0)
me32 = MODULEENTRY32()
me32.dwSize = sizeof( MODULEENTRY32 )
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ProcessID )
ret = Module32First( hModuleSnap, pointer(me32) )
if ret == 0 :
print 'ListProcessModules() Error on Module32First[%d]' % GetLastError()
CloseHandle( hModuleSnap )
return False
while ret :
print " MODULE NAME: %s"% me32.szModule
print " executable = %s"% me32.szExePath
print " process ID = 0x%08X"% me32.th32ProcessID
print " ref count (g) = 0x%04X"% me32.GlblcntUsage
print " ref count (p) = 0x%04X"% me32.ProccntUsage
print " base address = 0x%08X"% me32.modBaseAddr
print " base size = %d"% me32.modBaseSize
ret = Module32Next( hModuleSnap , pointer(me32) )
CloseHandle( hModuleSnap )
return True
I'm trying to transmit TCP/IP over a radio that is connected to my computer (specifically, the USRP). Right now, it's done very simply using Tun/Tap to set up a new network interface. Here's the code:
from gnuradio import gr, gru, modulation_utils
from gnuradio import usrp
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
from optparse import OptionParser
import random
import time
import struct
import sys
import os
# from current dir
from transmit_path import transmit_path
from receive_path import receive_path
import fusb_options
#print os.getpid()
#raw_input('Attach and press enter')
# Linux specific...
# TUNSETIFF ifr flags from <linux/tun_if.h>
IFF_TUN = 0x0001 # tunnel IP packets
IFF_TAP = 0x0002 # tunnel ethernet frames
IFF_NO_PI = 0x1000 # don't pass extra packet info
IFF_ONE_QUEUE = 0x2000 # beats me ;)
def open_tun_interface(tun_device_filename):
from fcntl import ioctl
mode = IFF_TAP | IFF_NO_PI
TUNSETIFF = 0x400454ca
tun = os.open(tun_device_filename, os.O_RDWR)
ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode))
ifname = ifs[:16].strip("\x00")
return (tun, ifname)
# /////////////////////////////////////////////////////////////////////////////
# the flow graph
# /////////////////////////////////////////////////////////////////////////////
class my_top_block(gr.top_block):
def __init__(self, mod_class, demod_class,
rx_callback, options):
gr.top_block.__init__(self)
self.txpath = transmit_path(mod_class, options)
self.rxpath = receive_path(demod_class, rx_callback, options)
self.connect(self.txpath);
self.connect(self.rxpath);
def send_pkt(self, payload='', eof=False):
return self.txpath.send_pkt(payload, eof)
def carrier_sensed(self):
"""
Return True if the receive path thinks there's carrier
"""
return self.rxpath.carrier_sensed()
# /////////////////////////////////////////////////////////////////////////////
# Carrier Sense MAC
# /////////////////////////////////////////////////////////////////////////////
class cs_mac(object):
"""
Prototype carrier sense MAC
Reads packets from the TUN/TAP interface, and sends them to the PHY.
Receives packets from the PHY via phy_rx_callback, and sends them
into the TUN/TAP interface.
Of course, we're not restricted to getting packets via TUN/TAP, this
is just an example.
"""
def __init__(self, tun_fd, verbose=False):
self.tun_fd = tun_fd # file descriptor for TUN/TAP interface
self.verbose = verbose
self.tb = None # top block (access to PHY)
def set_top_block(self, tb):
self.tb = tb
def phy_rx_callback(self, ok, payload):
"""
Invoked by thread associated with PHY to pass received packet up.
#param ok: bool indicating whether payload CRC was OK
#param payload: contents of the packet (string)
"""
if self.verbose:
print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload))
if ok:
os.write(self.tun_fd, payload)
def main_loop(self):
"""
Main loop for MAC.
Only returns if we get an error reading from TUN.
FIXME: may want to check for EINTR and EAGAIN and reissue read
"""
min_delay = 0.001 # seconds
while 1:
payload = os.read(self.tun_fd, 10*1024)
if not payload:
self.tb.send_pkt(eof=True)
break
if self.verbose:
print "Tx: len(payload) = %4d" % (len(payload),)
delay = min_delay
while self.tb.carrier_sensed():
sys.stderr.write('B')
time.sleep(delay)
if delay < 0.050:
delay = delay * 2 # exponential back-off
self.tb.send_pkt(payload)
# /////////////////////////////////////////////////////////////////////////////
# main
# /////////////////////////////////////////////////////////////////////////////
def main():
mods = modulation_utils.type_1_mods()
demods = modulation_utils.type_1_demods()
parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
expert_grp = parser.add_option_group("Expert")
parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
default='gmsk',
help="Select modulation from: %s [default=%%default]"
% (', '.join(mods.keys()),))
parser.add_option("-v","--verbose", action="store_true", default=False)
expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30,
help="set carrier detect threshold (dB) [default=%default]")
expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun",
help="path to tun device file [default=%default]")
transmit_path.add_options(parser, expert_grp)
receive_path.add_options(parser, expert_grp)
for mod in mods.values():
mod.add_options(expert_grp)
for demod in demods.values():
demod.add_options(expert_grp)
fusb_options.add_options(expert_grp)
(options, args) = parser.parse_args ()
if len(args) != 0:
parser.print_help(sys.stderr)
sys.exit(1)
if options.rx_freq is None or options.tx_freq is None:
sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
parser.print_help(sys.stderr)
sys.exit(1)
# open the TUN/TAP interface
(tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename)
# Attempt to enable realtime scheduling
r = gr.enable_realtime_scheduling()
if r == gr.RT_OK:
realtime = True
else:
realtime = False
print "Note: failed to enable realtime scheduling"
# If the user hasn't set the fusb_* parameters on the command line,
# pick some values that will reduce latency.
if options.fusb_block_size == 0 and options.fusb_nblocks == 0:
if realtime: # be more aggressive
options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024)
options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16)
else:
options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096)
options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16)
#print "fusb_block_size =", options.fusb_block_size
#print "fusb_nblocks =", options.fusb_nblocks
# instantiate the MAC
mac = cs_mac(tun_fd, verbose=True)
# build the graph (PHY)
tb = my_top_block(mods[options.modulation],
demods[options.modulation],
mac.phy_rx_callback,
options)
mac.set_top_block(tb) # give the MAC a handle for the PHY
if tb.txpath.bitrate() != tb.rxpath.bitrate():
print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % (
eng_notation.num_to_str(tb.txpath.bitrate()),
eng_notation.num_to_str(tb.rxpath.bitrate()))
print "modulation: %s" % (options.modulation,)
print "freq: %s" % (eng_notation.num_to_str(options.tx_freq))
print "bitrate: %sb/sec" % (eng_notation.num_to_str(tb.txpath.bitrate()),)
print "samples/symbol: %3d" % (tb.txpath.samples_per_symbol(),)
#print "interp: %3d" % (tb.txpath.interp(),)
#print "decim: %3d" % (tb.rxpath.decim(),)
tb.rxpath.set_carrier_threshold(options.carrier_threshold)
print "Carrier sense threshold:", options.carrier_threshold, "dB"
print
print "Allocated virtual ethernet interface: %s" % (tun_ifname,)
print "You must now use ifconfig to set its IP address. E.g.,"
print
print " $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,)
print
print "Be sure to use a different address in the same subnet for each machine."
print
tb.start() # Start executing the flow graph (runs in separate threads)
mac.main_loop() # don't expect this to return...
tb.stop() # but if it does, tell flow graph to stop.
tb.wait() # wait for it to finish
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
(Anyone familiar with GNU Radio will recognize this as tunnel.py)
My question is, is there a better way to move packets to and from the kernel than tun/tap? I've been looking at ipip or maybe using sockets, but I'm pretty sure those won't be very fast. Speed is what I'm most concerned with.
Remember that tunnel.py is a really, really rough example, and hasn't been updated in a while. It's not really meant to be a basis for other code, so be careful of how much you rely on the code.
Also, remember that TCP over unreliable radio links has significant issues:
http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_over_wireless_networks
I trying to write a client server application in Python, but I faced a problem, in the client side I'm not getting all the sent data. First I tried to send the numbers 1 to 10 and I received 1,2,5,6,10, so there are missing a lot of numbers.
Server side:
def __init__( self ):
super( MCCommunication, self ).__init__()
HOST, PORT = socket.gethostbyname( socket.gethostname() ), 31000
self.server = SocketServer.ThreadingTCPServer( ( HOST, PORT ), MCRequestHandler )
ip, port = self.server.server_address
# Start a thread with the server
# Future task: Make the server a QT-Thread...
self.server_thread = threading.Thread( target = self.server.serve_forever )
# Exit the server thread when the main thread terminates
self.server_thread.setDaemon( True )
self.textUpdated.emit( 'Server Started!' )
print( 'Server Started!' )
self.server_thread.start()
def handle( self ):
#self.request.setblocking( 0 )
i = 10;
while True:
if( self.clientname == 'MasterClient' ):
try:
#ans = self.request.recv( 4096 )
#print( 'after recv' )
""" Sendign data, testing purpose """
while i:
mess = str( i );
postbox['MasterClient'].put( self.creatMessage( 0, 0 , mess ) )
i = i - 1
while( postbox['MasterClient'].empty() != True ):
sendData = postbox['MasterClient'].get_nowait()
a = self.request.send( sendData )
print( a );
#dic = self.getMessage( sendData )
#print 'Sent:%s\n' % str( dic )
except:
mess = str( sys.exc_info()[0] )
postbox['MasterClient'].put( self.creatMessage( 1, 0 , mess ) )
pass
def creatMessage( self, type1 = 0, type2 = 0, message = ' ', extra = 0 ):
return pickle.dumps( {"type1":type1, "type2":type2, "message":message, "extra":extra} );
Where the postbox['MasterClient'] is a Queue with the serialized message.
And this is the client:
def run( self ):
sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
addr = ( self.ip, self.port )
#print addr
sock.connect( addr )
#sock.setblocking( 0 )
while True:
try:
ans = sock.recv( 4096 )
dic = self.getMessage( ans )
self.recvMessageHandler( dic )
print 'Received:%s\n' % str( dic )
except:
pass
The server may have sent multiple messages by the time the client attempts to read them, and if these fit within the same 4k buffer, the recv() call will obtain both of them.
You don't show the getMessage code, but I'd guess you're doing something like pickle.loads(msg), but this will only give you the first message and discard the rest of the string, hence the dropped messages. You'll also get another issue if more than 4096 bytes are buffered by the time you read, as you could end up getting a fragment of a message and thus an unpickling error.
You'll need to break up the string you get back into seperate messages, or better, just treat the socket as a stream and let pickle.load pull a single message from it.