2016-07-21 3 views
1

Если у меня есть пары IP-адреса, такие как:Кодировать два адреса IPv4 в 64 бита

IP1="168.2.65.33" 
IP2="192.4.2.55" 

Я хотел бы кодировать каждую пару в качестве 64-битового значения так, что первые 32 бита является первым IP-адрес и второй - второй IP-адрес. Затем мне хотелось бы сохранить 64-битное значение в файл таким образом, чтобы я мог его прочитать и восстановить два IP-адреса.

Цель - сэкономить место.

Возможно ли это сделать в python?

+0

@Hurkyl Спасибо. Исправлена. – eleanora

ответ

5

Не беспокойтесь о кодировании их в 64 бит. Адрес IPv4 - 32 бита (4 байта). Если вы напишете два файла в файл, размер будет 8 байтов.

Использования socket.inet_aton для преобразования удобочитаемого IP-адреса строки к упакованной бинарной сырой 4-байтовой строке:

import socket 
ip_addrs = ["168.2.65.33", "192.4.2.55"] 

with open('data.out', 'wb') as f: 
    for ip in ip_addrs: 
     raw = socket.inet_aton(ip) 
     f.write(raw) 

Результат:

$ hexdump -Cv data.out 
00000000 a8 02 41 21 c0 04 02 37       |..A!...7| 
00000008 

Комплементарное преобразование функция socket.inet_ntoa будет преобразовывать упакованную 4-байтную строку обратно в человеко-читаемый IP-адрес.


Вот пример написания и чтения их обратно:

import socket 

ip_pairs = [ 
    ('1.1.1.1', '1.1.1.2'), 
    ('2.2.2.2', '2.2.2.3'), 
    ('3.3.3.3', '3.3.3.4'), 
] 

# Write them out 
with open('data.out', 'wb') as f: 
    for ip1, ip2 in ip_pairs: 
     raw = socket.inet_aton(ip1) + socket.inet_aton(ip2) 
     f.write(raw) 

def read_with_eof(f, n): 
    res = f.read(n) 
    if len(res) != n: 
     raise EOFError 
    return res 

# Read them back in 
result = [] 
with open('data.out', 'rb') as f: 
    while True: 
     try: 
      ip1 = socket.inet_ntoa(read_with_eof(f, 4)) 
      ip2 = socket.inet_ntoa(read_with_eof(f, 4)) 
      result.append((ip1, ip2)) 
     except EOFError: 
      break 

print 'Input:', ip_pairs 
print 'Result:', result 

Выход:

$ python pairs.py 
Input: [('1.1.1.1', '1.1.1.2'), ('2.2.2.2', '2.2.2.3'), ('3.3.3.3', '3.3.3.4')] 
Result: [('1.1.1.1', '1.1.1.2'), ('2.2.2.2', '2.2.2.3'), ('3.3.3.3', '3.3.3.4')] 
+0

Как бы вы тогда их прочесть? У меня много тысяч таких пар, которые мне нужно сохранить. – eleanora

+0

@eleanora: Если у вас есть байтовая строка из 8 байтов, считанных из файла, используйте 'socket.inet_ntoa (s [: 4])', чтобы получить удобочитаемую версию 1-го IP-адреса. – pts

+0

@eleanora Я добавил пример их чтения. –

1

Да, это возможно, как это:

import struct 
import os 
IP1="168.2.65.233" 
IP2="192.4.2.55" 
s = struct.pack('>8B', *map(int, IP1.split('.') + IP2.split('.'))) 
with open('f', 'wb') as f: 
    f.write(s) 
print(os.stat('f').st_size) #: 8. 

это работает в Python 2 и 3.

Основываясь на ответе Джонатона Рейнхарта, вы также можете использовать socket.inet_aton вместо struct.pack.

1

В Python3 имеется модуль ipaddress для работы с IP-адресами. Упакуйте их в 32 бита каждый, и добавить их вместе:

from ipaddress import ip_address 

original1 = ip_address('192.168.0.1') 
original2 = ip_address('8.8.8.8') 

out = original1.packed + original2.packed 

Загрузите их обратно:

loaded1 = ip_address(out[0:4]) 
loaded2 = ip_address(out[4:]) 

Попробуйте онлайн: https://repl.it/Ce3k/1

Смежные вопросы