Python Networking!
This commit is contained in:
parent
a593761b2d
commit
b28c9925b9
133
main.py
133
main.py
@ -1,7 +1,126 @@
|
||||
import mymodule as m
|
||||
x = m.gtime()
|
||||
print(x.year)
|
||||
print(type(x))
|
||||
print(x.strftime("%A"))
|
||||
y = m.mdate(2022, 11, 30)
|
||||
print(y)
|
||||
#BSD 3-Clause, (C) Alfred Manville 2022
|
||||
import networker as net
|
||||
import sys
|
||||
from threading import Thread
|
||||
import traceback
|
||||
|
||||
translators = (net.PickleTranslate(), net.JSONTranslate())
|
||||
|
||||
inter = ""
|
||||
port = 0
|
||||
translator = None
|
||||
conn = None
|
||||
allowFiles = False
|
||||
log = []
|
||||
|
||||
def onConn(addr):
|
||||
log.append(addr + " # Connection Established")
|
||||
|
||||
def onEnd(addr):
|
||||
log.append(addr + " # Connection Ended")
|
||||
|
||||
def onRecv(addr, msg):
|
||||
global allowFiles
|
||||
if type(msg) != net.Message:
|
||||
log.append("Invalid Message received from: " + addr)
|
||||
return
|
||||
if msg.mtype == net.MTYPE_Text:
|
||||
log.append(addr + " ; " + str(msg.header) + " ; " + str(msg.content))
|
||||
elif msg.mtype == net.MTYPE_File:
|
||||
if allowFiles:
|
||||
log.append(addr + " ; " + str(msg.header))
|
||||
msg.saveContent()
|
||||
else:
|
||||
log.append(addr + " ; File Rejected")
|
||||
else:
|
||||
log.append("Unknown Message type received from: " + addr)
|
||||
|
||||
def main():
|
||||
global allowFiles
|
||||
conn = net.Connection((inter, port), translator, onConn, onRecv, onEnd)
|
||||
ct = Thread(target=conn.listener, args=())
|
||||
ct.start()
|
||||
print("Listener started @ " + inter + ":" + str(port))
|
||||
print("Format: \"command;ip:port;argument\"")
|
||||
print("Commands: connect, disconnect, list, log, file_allowed, toggle_file_allowed, message, send, help, exit")
|
||||
while conn.active:
|
||||
cmd = input("> ").lower()
|
||||
csplt = cmd.split(";", 2)
|
||||
try:
|
||||
if len(csplt) > 0:
|
||||
if csplt[0] == "list":
|
||||
print(conn.addresses())
|
||||
continue
|
||||
elif csplt[0] == "help":
|
||||
print("Help:")
|
||||
print("connect;ip:port -- Connects to the specified IP:Port")
|
||||
print("disconnect;ip:port -- Disonnects from the specified IP:Port")
|
||||
print("list -- Lists the available IP:Port connections")
|
||||
print("log -- Gets the message log")
|
||||
print("file_allowed -- Gets if file receiving is allowed")
|
||||
print("toggle_file_allowed -- Toggles if file receiving is allowed")
|
||||
print("message;ip:port;header:body -- Sends a message to the specified IP:Port")
|
||||
print("send;ip:port;path -- Sends a file message to the specified IP:Port")
|
||||
print("help -- Shows this message")
|
||||
print("exit -- Exits this program closing all connections")
|
||||
continue
|
||||
elif csplt[0] == "exit":
|
||||
conn.close()
|
||||
break
|
||||
elif csplt[0] == "log":
|
||||
while len(log) > 0:
|
||||
print(log.pop(0))
|
||||
continue
|
||||
elif csplt[0] == "file_allowed":
|
||||
print("Receive File Status: " + str(allowFiles))
|
||||
continue
|
||||
elif csplt[0] == "toggle_file_allowed":
|
||||
allowFiles = not allowFiles
|
||||
print("Receive File Status set to: " + str(allowFiles))
|
||||
continue
|
||||
if len(csplt) > 1:
|
||||
if csplt[0] == "connect":
|
||||
print("Attempting Connection to: " + csplt[1])
|
||||
ippsplt = csplt[1].split(":", 1)
|
||||
conn.connect((ippsplt[0], int(ippsplt[1])))
|
||||
continue
|
||||
elif csplt[0] == "disconnect":
|
||||
print("Attempting Disconnection from: " + csplt[1])
|
||||
conn.actives[csplt[1]] = False
|
||||
conn.sockets[csplt[1]].close()
|
||||
continue
|
||||
if len(csplt) > 2:
|
||||
if csplt[0] == "message":
|
||||
datasplt = csplt[2].split(":", 1)
|
||||
print("Attempting to send message to: " + csplt[1])
|
||||
conn.send(csplt[1], net.Message(net.MTYPE_Text, datasplt[0], datasplt[1]))
|
||||
continue
|
||||
elif csplt[0] == "send":
|
||||
print("Attempting to send file to: " + csplt[1])
|
||||
conn.send(csplt[1], net.Message(net.MTYPE_File, csplt[2], None))
|
||||
continue
|
||||
print("Invalid Command!")
|
||||
|
||||
except Exception as e:
|
||||
print("Command Error!")
|
||||
print(traceback.format_exc())
|
||||
exit
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Python Communicator (C) Alfred Manville 2022 BSD-3-Clause")
|
||||
if len(sys.argv) > 1:
|
||||
inter = sys.argv[1]
|
||||
else:
|
||||
inter = input("Enter the listening interface: ")
|
||||
if len(sys.argv) > 2:
|
||||
port = int(sys.argv[2])
|
||||
else:
|
||||
port = int(input("Enter the listening port: "))
|
||||
if len(sys.argv) > 3:
|
||||
translator = translators[int(sys.argv[3]) - 1]
|
||||
else:
|
||||
translator = translators[int(input("Enter the message translator position " + str(translators) + " : ")) - 1]
|
||||
main()
|
||||
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
from datetime import datetime as dt
|
||||
def gtime():
|
||||
return dt.now()
|
||||
def mdate(y, mo, d):
|
||||
return dt(y, mo, d)
|
223
networker.py
Normal file
223
networker.py
Normal file
@ -0,0 +1,223 @@
|
||||
#BSD 3-Clause, (C) Alfred Manville 2022
|
||||
import pickle
|
||||
import json
|
||||
import socket
|
||||
import time
|
||||
from threading import Thread
|
||||
import base64
|
||||
import traceback
|
||||
|
||||
#Defines a message class that has a type, header and a body.
|
||||
class Message:
|
||||
|
||||
def __init__(self, mtype, header, content):
|
||||
self.mtype = mtype
|
||||
self.header = header
|
||||
if mtype == MTYPE_File:
|
||||
try:
|
||||
f = open(header, "r")
|
||||
try:
|
||||
self.content = str(f.read())
|
||||
except:
|
||||
print("An issue writing the message for \"" + self.header + "\" occured.")
|
||||
f.close()
|
||||
except:
|
||||
print("An issue when opening a file for reading: \"" + self.header + "\" occured.")
|
||||
else:
|
||||
self.content = content
|
||||
|
||||
def saveContent(self):
|
||||
if self.mtype != MTYPE_File: pass
|
||||
try:
|
||||
f = open(str(self.header), "w")
|
||||
try:
|
||||
f.write(bytes(self.content))
|
||||
except:
|
||||
print("An issue writing the message for \"" + str(self.header) + "\" occured.")
|
||||
f.close()
|
||||
except:
|
||||
print("An issue when opening a file for writing: \"" + str(self.header) + "\" occured.")
|
||||
|
||||
def toDict(self):
|
||||
toReturn = {"mtype":self.mtype, "header":self.header, "ident__":"Message"}
|
||||
if type(self.content) == bytes or type(self.content) == bytearray:
|
||||
toReturn["contentb64"] = True
|
||||
toReturn["content"] = base64.b64encode(bytes(self.content)).decode()
|
||||
else:
|
||||
toReturn["contentb64"] = False
|
||||
toReturn["content"] = self.content
|
||||
return toReturn
|
||||
|
||||
#Message from dict:
|
||||
def MessageFromDict(d):
|
||||
if type(d) != None and d.get("ident__") == "Message":
|
||||
if d.get("contentb64") != None:
|
||||
if d.get("contentb64"):
|
||||
return Message(int(d.get("mtype")),d.get("header"), base64.b64decode(d.get("content")))
|
||||
else:
|
||||
return Message(int(d.get("mtype")),d.get("header"), d.get("content"))
|
||||
print("Invalid message dictionary!")
|
||||
return None
|
||||
|
||||
#mtype Definitions:
|
||||
MTYPE_Text = 0;
|
||||
MTYPE_File = 1;
|
||||
|
||||
#Pickle Translator for Message to and from bytes.
|
||||
class PickleTranslate:
|
||||
def toString(self, m):
|
||||
try:
|
||||
return pickle.dumps(m)
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
return None
|
||||
def fromString(self, b):
|
||||
try:
|
||||
return pickle.loads(b)
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
return None
|
||||
|
||||
#JSON Translator for Message to and from bytes.
|
||||
class JSONTranslate:
|
||||
def toString(self, m):
|
||||
try:
|
||||
return json.dumps(m.toDict())
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
return None
|
||||
def fromString(self, b):
|
||||
try:
|
||||
return MessageFromDict(json.loads(b))
|
||||
except:
|
||||
print(traceback.format_exc())
|
||||
return None
|
||||
|
||||
#Connection class
|
||||
class Connection:
|
||||
active = True
|
||||
sockets = dict()
|
||||
threads = dict()
|
||||
actives = dict()
|
||||
def __init__(self, binder, translator, onconn, onrecv, onend):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.bind(binder)
|
||||
self.socket.listen(8)
|
||||
self.translator = translator
|
||||
self.onconn = onconn
|
||||
self.onrecv = onrecv
|
||||
self.onend = onend
|
||||
def listener(self):
|
||||
while self.active:
|
||||
s, a = self.socket.accept()
|
||||
ac = a[0] + ":" + str(a[1])
|
||||
try:
|
||||
self.onconn(str(ac))
|
||||
except:
|
||||
print("Failure to call onconn for: " + str(ac))
|
||||
self.sockets[str(ac)] = s
|
||||
self.actives[str(ac)] = True
|
||||
self.threads[str(ac)] = Thread(target=self.processor, args=(str(ac),))
|
||||
self.threads[str(ac)].start();
|
||||
self.socket.close()
|
||||
|
||||
def processor(self, addr):
|
||||
while self.active and self.actives[addr]:
|
||||
try:
|
||||
head = self.sockets[addr].recv(2)
|
||||
if type(head) == None or len(head) != 2:
|
||||
print("An issue reading the packet header has occured for: " + addr)
|
||||
break
|
||||
dataSize = 0
|
||||
try:
|
||||
dataSize = int(head[0]) * 256 + int(head[1])
|
||||
except:
|
||||
print("An issue reading the packet header has occured for: " + addr)
|
||||
break
|
||||
if dataSize < 1:
|
||||
continue
|
||||
data = bytearray()
|
||||
while dataSize > 0:
|
||||
dataL = self.sockets[addr].recv(dataSize)
|
||||
dataSize -= len(dataL)
|
||||
data.extend(dataL)
|
||||
try:
|
||||
self.onrecv(addr, self.translator.fromString(data))
|
||||
except:
|
||||
print("Failure to call onrecv for: " + addr)
|
||||
except:
|
||||
print("A network issue has occured for: " + addr)
|
||||
self.actives[addr] = False
|
||||
break
|
||||
self.onend(addr)
|
||||
|
||||
def send(self, addr, m):
|
||||
if self.active and self.actives[addr]:
|
||||
try:
|
||||
toSend = bytes(self.translator.toString(m))
|
||||
sendLength = len(toSend)
|
||||
if sendLength < 1:
|
||||
print("Message for: " + addr + " empty?")
|
||||
return
|
||||
if sendLength > 65535:
|
||||
print("Message for: " + addr + " too big!")
|
||||
return
|
||||
head = bytearray(2)
|
||||
head[0] = sendLength//256
|
||||
sendLength -= int(head[0])*256
|
||||
head[1] = sendLength
|
||||
sendLength = -2
|
||||
try:
|
||||
sendLength += self.sockets[addr].send(bytes(head))
|
||||
sendLength += self.sockets[addr].send(toSend)
|
||||
except:
|
||||
try:
|
||||
if sendLength >= 0:
|
||||
self.sockets[addr].send(bytes(len(toSend) - sendLength))
|
||||
except:
|
||||
print("A network issue has occured for: " + addr)
|
||||
self.actives[addr] = False
|
||||
except:
|
||||
print("A send failure has occured for: " + addr)
|
||||
|
||||
def close(self):
|
||||
self.active = False
|
||||
for x in self.actives: self.actives[x] = False
|
||||
for x in self.sockets: self.sockets[x].close()
|
||||
ndone = True
|
||||
while ndone:
|
||||
ndone = False
|
||||
for x in self.threads:
|
||||
if self.threads[x].is_alive():
|
||||
ndone = True
|
||||
break
|
||||
time.sleep(0.0001)
|
||||
self.threads.clear()
|
||||
self.socket.close()
|
||||
|
||||
def addresses(self):
|
||||
if self.active:
|
||||
tL = []
|
||||
for x in self.actives:
|
||||
if self.actives[x]:
|
||||
tL.append(x)
|
||||
return tL
|
||||
else:
|
||||
return []
|
||||
|
||||
def connect(self, target):
|
||||
ac = target[0]+":"+str(target[1])
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(target)
|
||||
try:
|
||||
self.onconn(str(ac))
|
||||
except:
|
||||
print("Failure to call onconn for: " + str(ac))
|
||||
self.sockets[str(ac)] = s
|
||||
self.actives[str(ac)] = True
|
||||
self.threads[str(ac)] = Thread(target=self.processor, args=(str(ac),))
|
||||
self.threads[str(ac)].start()
|
||||
except:
|
||||
print("A connection error has occured for: " + ac)
|
||||
|
Loading…
Reference in New Issue
Block a user