Skip to content

Commit 653dad2

Browse files
authored
Merge pull request #4 from KrishnanSG/networking
Interact, a basic working version. (v1.0)
2 parents 4e0566c + ca59b1a commit 653dad2

File tree

11 files changed

+885
-26
lines changed

11 files changed

+885
-26
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# output BloomFilter file
2+
*.bin
3+
14
# Byte-compiled / optimized / DLL files
25
__pycache__/
36
*.py[cod]
@@ -86,6 +89,7 @@ celerybeat-schedule
8689
.venv
8790
env/
8891
venv/
92+
*venv/
8993
ENV/
9094
env.bak/
9195
venv.bak/

BloomFilter.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,39 @@ def __init__(self, n):
1616
self.size = math.ceil(-n*math.log(self.p)/(math.log(2)**2))
1717
self.k = math.ceil(self.size/n*math.log(2))
1818
self.bit_array = [0] * self.size
19+
self.validate_array = []
1920

2021
# Func to insert values into BF
21-
def insert(self, value):
22+
def insert(self, value, freq=1):
23+
line_hash = str(mmh3.hash(value,freq))
2224
for i in range(self.k):
23-
index = mmh3.hash(value, i) % self.size
25+
index = mmh3.hash(line_hash,i) % self.size
2426
self.bit_array[index] = 1
2527

2628
# To check if the value is present in BF or not
27-
def validate(self, value):
29+
def validate(self, value, freq=1):
30+
line_hash = str(mmh3.hash(value,freq))
2831
for i in range(self.k):
29-
check_at_index = mmh3.hash(value, i) % self.size
30-
if self.bit_array[check_at_index] == 1:
32+
check_at_index = mmh3.hash(line_hash,i) % self.size
33+
if self.validate_array[check_at_index] == 1:
3134
continue
3235
else:
3336
return False
3437
return True
3538

39+
def readBloomFilterFromFile(self,filename):
40+
f = open(filename, "rb")
41+
self.validate_array = list(f.read())
42+
for i in range(0, len(self.validate_array)):
43+
self.validate_array[i] -= 48
44+
print(self.validate_array)
45+
f.close()
46+
47+
def readBloomFilterFromBytes(self,bf_as_bytes):
48+
self.validate_array = list(bf_as_bytes)
49+
for i in range(0, len(self.validate_array)):
50+
self.validate_array[i] -= 48
51+
3652
# Returns the bit array
3753
def getBloomFilter(self):
3854
return self.bit_array
@@ -41,6 +57,12 @@ def getBloomFilter(self):
4157
def getSize(self):
4258
return self.size
4359

60+
def getNFromSize(self,size):
61+
return(math.floor(size*-1*(math.log(2)**2)/math.log(self.p)))
62+
4463
# Returns the # of Hash Functions ie. h1(k), h2(k) ...
4564
def getNumberOfHashFunctions(self):
4665
return self.k
66+
67+
def getAsBytes(self):
68+
return str.encode(''.join([str(i) for i in self.bit_array]))

P2P/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## Messaging format
2+
3+
Each message will have this format
4+
```
5+
1. First byte specifying the message type - int.
6+
- `2` - Bloom filter request message from client to server - server should reply with type `3` followed by the bloomfilter.
7+
- `3` - Denotes that a bloom filter is incoming
8+
- `4` - Denotes that the actual changes are coming through in that request
9+
10+
```
11+
12+
Maybe pad all the messages with some delimiter bytes to seperate the different requests
13+
14+
Once the BF is exchanged
15+
1. Call getMissingContent for both users
16+
2. Send the missing contents of user 1 to user 2
17+
3. Call merge function on user2 side
18+
4. Send entire file sha256 and check on both ends
19+
if equal
20+
done
21+
else
22+
send the entire file

P2P/Server.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import socket
2+
import sys
3+
import time
4+
5+
from . import utils
6+
7+
MAX_RECEIVABLE_CONTENT_SIZE = 500000
8+
class NetworkManager:
9+
10+
# Variable to tell if the current user is host or client
11+
status = ""
12+
queue = []
13+
14+
def __init__(self, request_handler):
15+
self.handler = request_handler
16+
17+
def check_if_incoming_data(self):
18+
try:
19+
data = self.socket.recv(MAX_RECEIVABLE_CONTENT_SIZE)
20+
req = utils.parse_received_data(data)
21+
self.handler.handle_request(req)
22+
return tuple([00, ''])
23+
except BlockingIOError as e:
24+
# print(e)
25+
# No data to read
26+
return tuple([00, ''])
27+
except (ConnectionResetError, ValueError) as e:
28+
## ValueError is raised from parse_received_data
29+
print("\n\nUh-oh. looks like peer has closed the connection :(")
30+
exit()
31+
32+
def send_request(self, request):
33+
self.socket.send(request.get_type_byte() + request.get_message_bytes())
34+
35+
def create_host(self):
36+
self.status="host"
37+
server = socket.socket()
38+
host = socket.gethostname()
39+
40+
server.bind((host, 5050))
41+
self.socket = server
42+
print("\nHi ",host," we have hosted the server at")
43+
print("IP:",server.getsockname()[0])
44+
print("Port:",server.getsockname()[1])
45+
print("Share IP and Port with your friend to start sync.\n")
46+
server.listen()
47+
48+
c, client_addr = server.accept()
49+
self.socket = c
50+
print("Incoming request from", client_addr, "...")
51+
print("Connected to ", client_addr, "!")
52+
c.setblocking(False)
53+
54+
55+
def create_client(self,ip,port):
56+
self.status="client"
57+
client = socket.socket()
58+
self.socket = client
59+
host = socket.gethostname()
60+
client.connect((ip,port))
61+
client.setblocking(False)
62+
print("\nHi ",host," you are succesfully connected to")

P2P/__init__.py

Whitespace-only changes.

P2P/received_file

Whitespace-only changes.

P2P/utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
2+
3+
4+
class Request:
5+
6+
REQUEST_TYPE_BLOOMFILTER = 2
7+
REQUEST_TYPE_REPLY_SLAVE_BLOOMFILTER = 3
8+
REQUEST_SEND_ACTUAL_LINES = 4
9+
REQUEST_SEND_ENTIRE_FILE_HASH = 5
10+
REQUEST_SEND_ENTIRE_FILE = 6
11+
12+
def __init__(self, request_type, message):
13+
self.type = request_type
14+
self.message = message
15+
if isinstance(message, str):
16+
self.byte_message = bytes(message, 'utf-8')
17+
elif isinstance(message, bytes) :
18+
self.byte_message = message
19+
else:
20+
self.byte_message = bytes(message)
21+
22+
def get_type_byte(self):
23+
return bytes([self.type])
24+
25+
def get_type(self):
26+
return self.type
27+
28+
def get_message_size(self):
29+
return len(self.actual_message())
30+
31+
def actual_message(self):
32+
return self.byte_message.decode('utf-8')
33+
34+
def get_message_bytes(self):
35+
return self.byte_message
36+
37+
def __str__(self):
38+
return "<Request type: " + str(self.type) + ", message: " + self.actual_message() + "...>"
39+
40+
41+
42+
def parse_received_data(data):
43+
type_specifying_byte = data[0:1]
44+
bloom_filter = data[1:]
45+
try:
46+
str_message = bloom_filter.decode('utf-8')
47+
except UnicodeDecodeError:
48+
# Occurs sometimes when the contents received are not in utf-8
49+
# This can happen for example, when transmitting the hash value.
50+
str_message = bloom_filter
51+
print(bytes.hex(type_specifying_byte))
52+
type_int = int(bytes.hex(type_specifying_byte), 16)
53+
req = Request(type_int, str_message)
54+
return req

Synchronizer.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import mmh3
2+
def syncFile(filename,my_missing_content,received_missing_content):
3+
4+
file_content=[]
5+
contents_to_modify=[]
6+
7+
# Read file
8+
with open(filename,'r') as f:
9+
file_content=f.readlines()
10+
11+
for i in received_missing_content:
12+
if i in my_missing_content:
13+
# Present so update contents
14+
file_content[i-1]=received_missing_content[i]
15+
del(my_missing_content[i])
16+
else:
17+
# Not Present so insert no line
18+
# lines_to_insert.append(i)
19+
contents_to_modify.append([i,'i',received_missing_content[i]])
20+
21+
for i in my_missing_content.keys():
22+
contents_to_modify.append([i,'d'])
23+
contents_to_modify.sort()
24+
25+
def update_lines(flag):
26+
for i in range(len(contents_to_modify)):
27+
if contents_to_modify[i][1]=='d':
28+
contents_to_modify[i][0]+=flag
29+
30+
31+
while contents_to_modify:
32+
i=contents_to_modify.pop(0)
33+
# Insert
34+
if i[1]=='i':
35+
file_content.insert(i[0]-1,i[2])
36+
update_lines(1)
37+
# Delete
38+
else:
39+
file_content.pop(i[0]-1)
40+
update_lines(-1)
41+
42+
# Write into file
43+
with open(filename,'w') as f:
44+
f.writelines(file_content)
45+
46+
def computeHash(filename):
47+
# returns 4 byte hash value of the file
48+
file_reader = open(filename,"rb")
49+
file_contents = file_reader.read()
50+
n=abs(mmh3.hash(file_contents)) % 2**32
51+
return (n.to_bytes((n.bit_length()+7)//8,'big'))
52+

0 commit comments

Comments
 (0)