-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
298 lines (256 loc) · 10.4 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @@@@@@@@@ Server.py by Syed Afraz & Muhammad Abdullah @@@@@@@@@
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
from socket import *
import sys
import time
import multiprocessing
import subprocess
import math
import os
from os import path
from stat import * # ST_SIZE etc
import threading
"""IMPORTANT README"""
# Run script using the following command in linux terminal.
# python3 server.py -i 2 -n 4 -f <fileName.mp4> -a <Your IP Address> -p 21018 27215 35416 19222 39223
class Server:
'Common base class for all servers.'
# --------- Global Variables ---------
serverIpAddr = "" # Constructor updates this.
splitSize = 12 # Divide a file into these many parts(User can provide)
serverNumber = 1 # Will be re-assigned by constructor.
liveStatus = "Alive" # Status toggled on/off
shutdown = [False, False, False, False]
# shutdown list is shared between instances, i.e. if one object changes it, the change is reflected to all objects. It starts with all False because all servers are up initially.
# --------- Constructor ---------
def __init__(self, splitSize, serverNumber, serverIpAddr):
self.splitSize = splitSize
self.serverNumber = serverNumber
self.serverIpAddr = serverIpAddr
# print("Constructing server...")
# ----------------------------------------
# --------- Segmenting video file --------
# ----------------------------------------
# This function is used to divide the length(in bytes) of a mp4 file by a constant to create a variable called splitCount. Next, a for loop is used that runs from 0 to total length. Each iteration is splitCount apart. Inside the loop we use a conditional that identifies if we're on the last segment because the size of the last segment differs from all other segments. Lastly, we create and save each file with its respective size.
def ceilDiv(self, a, b):
return int(math.ceil(a / float(b)))
def segmentation(self, fileName):
try:
file = open(fileName, "rb")
data = file.read()
splitCount = self.ceilDiv(len(data), self.splitSize)
# print("file size:", st[ST_SIZE])
# print(ceilDiv(st[ST_SIZE], 12))
j = 1
for i in range(0, len(data), splitCount):
chunk = data[i:i + splitCount]
f = open("segment" + str(j) + ".mp4", "wb")
if i == (self.splitSize - 1) * splitCount:
lastSplit = len(data) - ((self.splitSize - 1) * splitCount)
chunk = data[i:i + lastSplit]
f.write(chunk)
else:
f.write(chunk)
j += 1
f.close()
file.close()
except IOError:
print("failed to get information about", fileName)
# ----------------------------------------
# - Socket Programming for Server 1 to 4 -
# ----------------------------------------
def serverProgram(self, chosenPort):
serverPort = chosenPort
serverIP = self.serverIpAddr
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind((serverIP, serverPort))
serverSocket.listen(5)
liveStatus = "Alive"
conn, address = serverSocket.accept()
while True:
try:
# print("Connection from: " + str(address))
data = conn.recv(4096)
# Decode received data into UTF-8
data = data.decode('utf-8')
# Convert decoded data into list
data = eval(data)
if (self.liveStatus == "Dead"):
# print("Im here")
continue
# print(data)
file1 = open("segment"+str(data[0])+".mp4", "rb")
fileData = file1.read(100000000)
conn.send(fileData)
# print("Segment "+str(data[0]) +
# " sent by " + str(self.serverNumber))
continue
except Exception as e:
# Block runs when all segments asked by client have been sent.
# Do last minute programming here
# print("Server "+str(self.serverNumber)+" list over")
continue
# print("Server not listening")
# serverSocket.close()
# ---------------------------------------
# --- Socket Programming for Server 5 ---
# ---------------------------------------
def closingServer(self, chosenPort):
serverPort = chosenPort
serverIP = self.serverIpAddr
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind((serverIP, serverPort))
serverSocket.listen(5)
conn, address = serverSocket.accept()
tempArray = []
while True:
try:
# print("Connection from: " + str(address))
# x1 is a boolean list that tells which servers are down.
x1 = []
for x in range(len(self.shutdown)): # Loop to populate x1
if (self.shutdown[x] == True):
x1.append(0)
# self.shutdown[x] = False
else:
x1.append(1)
if(tempArray == x1): # If list is same as before, continue
continue
else: # If list different, send its contents.
x1 = str(x1)
x1 = x1.encode()
conn.send(x1)
except Exception as e:
# print("Server 5 connection over.")
raise e # Throws exception to try/except in runServer5 block
break
# Function to carry out the finsihing tasks(updating shutdown array etc..) before a server is forecfully shutdown.
def kill(self):
self.liveStatus = "Dead"
self.shutdown[self.serverNumber-1] = True
# Function to carry out the starting tasks(updating shutdown array etc..) before a server is forecfully woken up.
def alive(self):
self.liveStatus = "Alive"
self.shutdown[self.serverNumber-1] = False
# ----------------------------------------
# ------------- Main function ------------
# ----------------------------------------
def main():
# --------- Retrieve info from the terminal command ---------
argSize = len(sys.argv)
argList = sys.argv
# print(argSize, argList)
# --------- Constants ---------
STATUS_INTERVAL = int(argList[2])
NUM_OF_SERVERS = int(argList[4])
PORT_NUMBERS = []
FILE_NAME = argList[6]
SERVER_IP = argList[8]
# PORT_NUMBERS = [21018, 27215, 35416, 19222, 39223]
# --------- Populating PORT_NUMBERS with 'n' number of ports ---------
for n in range(10, argSize):
port = int(argList[n])
PORT_NUMBERS.append(port)
# Creating 5 instances of Servers with args as splitSize and serverNumber and common IP Address
Server1 = Server(12, 1, SERVER_IP)
Server2 = Server(12, 2, SERVER_IP)
Server3 = Server(12, 3, SERVER_IP)
Server4 = Server(12, 4, SERVER_IP)
Server5 = Server(12, 5, SERVER_IP)
# Server 1 is responsible of segmentation.
Server1.segmentation(FILE_NAME)
# Function to safely exit program.
def exitProgram():
p1.terminate()
p2.terminate()
p3.terminate()
p4.terminate()
os._exit(os.EX_OK)
# Function to create Server 1, also responsible of file SEGMENTATION
def runServer1():
Server1.serverProgram(PORT_NUMBERS[0])
# Function to create Server 2 only.
def runServer2():
Server2.serverProgram(PORT_NUMBERS[1])
# Function to create Server 3 only.
def runServer3():
Server3.serverProgram(PORT_NUMBERS[2])
# Function to create Server 4 only.
def runServer4():
Server4.serverProgram(PORT_NUMBERS[3])
def runServer5():
try:
Server5.closingServer(PORT_NUMBERS[4])
except Exception as e:
exitProgram()
# ------------- Output function ------------
def output():
while True:
print("\n ---------------------")
print("MultiServer Downloader")
print(" ---------------------")
print("Server 1 at Port: " +
str(PORT_NUMBERS[0]) + " Status: " + Server1.liveStatus + " To shutdown/wakeup enter 1")
print("Server 2 at Port: " +
str(PORT_NUMBERS[1]) + " Status: " + Server2.liveStatus + " To shutdown/wakeup enter 2")
print("Server 3 at Port: " +
str(PORT_NUMBERS[2]) + " Status: " + Server3.liveStatus + " To shutdown/wakeup enter 3")
print("Server 4 at Port: " +
str(PORT_NUMBERS[3]) + " Status: " + Server4.liveStatus + " To shutdown/wakeup enter 4")
print("To quit, enter -1: ")
val = int(input("\nEnter your Choice: "))
if val == 1:
if (Server1.liveStatus == "Alive"):
Server1.kill()
else:
Server1.alive()
elif val == 2:
if (Server2.liveStatus == "Alive"):
Server2.kill()
else:
Server2.alive()
elif val == 3:
if (Server3.liveStatus == "Alive"):
Server3.kill()
else:
Server3.alive()
elif val == 4:
if (Server4.liveStatus == "Alive"):
Server4.kill()
else:
Server4.alive()
elif val == -1:
exitProgram()
else:
print("Wrong input, try again..")
os.system("clear")
# 4 processes and 2 thread created.
p1 = multiprocessing.Process(target=runServer1)
p2 = multiprocessing.Process(target=runServer2)
p3 = multiprocessing.Process(target=runServer3)
p4 = multiprocessing.Process(target=runServer4)
t1 = threading.Thread(target=runServer5)
t2 = threading.Thread(target=output)
p1.start()
time.sleep(0.04)
p2.start()
time.sleep(0.04)
p3.start()
time.sleep(0.04)
p4.start()
time.sleep(0.04)
t1.start()
time.sleep(0.04)
t2.start()
p1.join()
p2.join()
p3.join()
p4.join()
t1.join()
t2.join()
# Driver code
if __name__ == "__main__":
main()