2009-10-19 6 views
1

J'écris une application pour analyser certains paquets réseau. Un champ de paquet contient le numéro de version du protocole dans un octet, de sorte que 4 bits hauts sont les «majeurs» et les 4 faibles sont la version «mineure». Actuellement, je les analyse comme suit, mais me demande s'il y a une façon de faire plus jolie ou plus « pythonique » il:Quelle est la manière correcte de traiter 4 bits dans un octet en python?

v = ord(data[17]) 
    major = (v & int('11110000',2)) >> 4 
    minor = v & int('00001111',2) 

Répondre

2

Vous pouvez écrire littéraux binaires comme celui-ci 0b1111000

Pour votre exemple, je voudrais proabbly utiliser hex si

v = ord(data[17]) 
major = (v & 0xF0) >> 4 
minor = (v & 0x0F) 

Vous pouvez également utiliser le module struct pour briser le paquet dans ses composants

+0

0v11110000 ne fonctionne pas comme je suis coincé avec 2,4 python, mais en utilisant hexadécimal est logique, grâce – Kimvais

+0

Oh oui, et merci pour la pointe struct! – Kimvais

1

Il serait plus facile d'utiliser des littéraux au lieu d'appeler int. Vous pouvez utiliser les littéraux binaires ou hexagonal, par exemple:

major = (v & 0xf0) >> 4 
minor = (v & 0x0f) 

littéraux binaires ne fonctionnent que pour Python 2.6 ou version ultérieure et sont de la forme 0b11110000. Si vous utilisez Python 2.6 ou version ultérieure, vous voudrez peut-être regarder le type bytearray car cela vous permettra de traiter les données comme binaires et de ne pas avoir à utiliser l'appel à ord.

Si vous analysez des données binaires et constatez que vous devez effectuer de nombreuses manipulations de bits, vous pouvez essayer une solution plus générale car certains modules tiers sont spécialisés dans ce domaine. L'un est hachoir, et une alternative de niveau inférieur est bitstring (que j'ai écrit). Dans ce votre analyse deviendrait quelque chose comme:

major, minor = data.readlist('uint:4, uint:4') 

qui peut être plus facile à gérer si vous faites beaucoup de ces lectures.

0

Juste un soupçon, vous feriez mieux d'appliquer le masque pour le majeur après déplacement, dans le cas où il est un nombre négatif et le signe est maintenu:

major = (v >> 4) & 0x0f 
minor = (v & 0x0f) 
+0

Votre syntaxe semble invalide, et je pense qu'ord ne retournera jamais un nombre positif. –

+0

Je suis content de voir que vous êtes un bon spotting typos ... lorsque vous jouez avec des bitmasks, il est préférable de s'assurer que votre code est robuste contre des éventualités comme un changement d'interface (je ne m'attends pas à changer, mais ce n'est pas peu probable que cet extrait puisse être refactorisé et avoir un bogue causé par une expansion de signe alors que le décalage vers la gauche est plus difficile à repérer qu'une syntaxe invalide) – fortran

+0

Désolé, mais je ne peux pas voir quand '(v >> 4) & 0x0f' être différent de '(v & 0xf0) >> 4' (pouvez-vous donner un exemple?). Dans certaines langues, le décalage vers la gauche (plutôt que vers la droite) peut entraîner la définition d'un bit de poids fort qui pourrait modifier le signe, mais cela ne se produira pas avec les entiers en Python. –

2

fonctions bien nommées sont toujours une bonne façon pour cacher la laideur et la complexité non pertinente. De cette façon, le jeu de bits est confiné à de petites fonctions correctes et facilement éprouvées tandis que le code de niveau supérieur peut se référer à l'objectif du violon.

def high_nibble(byte): 
    """Get 4 high order bits from a byte.""" 
    return (byte >> 4) & 0xF 

def low_nibble(byte): 
    """Get 4 low order bits from a byte.""" 
    return byte & 0xF 

def parse_version(version_byte): 
    """Get the major-minor version tuple from the version byte.""" 
    return high_nibble(version_byte), low_nibble(version_byte) 

major, minor = parse_version(version_byte) 
Questions connexes