Initial commit
This commit is contained in:
commit
a46242999b
|
@ -0,0 +1,8 @@
|
|||
# Editors
|
||||
.idea/
|
||||
|
||||
# Caches
|
||||
__pycache__/
|
||||
|
||||
# Virtual environments
|
||||
venv/
|
|
@ -0,0 +1,26 @@
|
|||
__author__ = "Kieran Osborne"
|
||||
__version__ = "0.0.1"
|
||||
__status__ = "Development"
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
import config
|
||||
import socket as network
|
||||
import message
|
||||
|
||||
def init() -> None:
|
||||
address = (config.host, config.port)
|
||||
|
||||
print("Starting connection to", address)
|
||||
|
||||
with network.socket(network.AF_INET, network.SOCK_STREAM) as socket:
|
||||
socket.setblocking(False)
|
||||
socket.connect_ex(address)
|
||||
|
||||
while True:
|
||||
message_body = input("Enter a message: ")
|
||||
|
||||
print("\n")
|
||||
socket.send(message.serialize("Kayomn", message_body))
|
||||
|
||||
init()
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
__author__ = "Kieran Osborne"
|
||||
__version__ = "0.0.1"
|
||||
__status__ = "Development"
|
||||
|
||||
host = "127.0.0.1"
|
||||
port = 12345
|
|
@ -0,0 +1,32 @@
|
|||
import sys
|
||||
import json
|
||||
import struct
|
||||
|
||||
|
||||
class Message:
|
||||
def __init__(self, author: str, body: str) -> None:
|
||||
self.author = author
|
||||
self.body = body
|
||||
|
||||
def serialize(self) -> bytes:
|
||||
return serialize(self.author, self.body)
|
||||
|
||||
|
||||
def deserialize(data: bytes) -> Message:
|
||||
buffer_length = 2
|
||||
header_length = struct.unpack(">H", data[:buffer_length])[0]
|
||||
header = json.loads(data[buffer_length:header_length])
|
||||
|
||||
return Message(header["author"], header["encoded-body"])
|
||||
|
||||
|
||||
def serialize(author: str, body: str) -> bytes:
|
||||
encoding = sys.getdefaultencoding()
|
||||
|
||||
header_bytes = json.dumps({
|
||||
"byteorder": sys.byteorder,
|
||||
"author": author,
|
||||
"body": encoding,
|
||||
}).encode("utf-8")
|
||||
|
||||
return (struct.pack(">H", len(header_bytes)) + header_bytes)
|
|
@ -0,0 +1,104 @@
|
|||
__author__ = "Kieran Osborne"
|
||||
__version__ = "0.0.1"
|
||||
__status__ = "Development"
|
||||
|
||||
if (__name__ == "__main__"):
|
||||
import config
|
||||
import traceback
|
||||
import socket as network
|
||||
import selectors
|
||||
import message
|
||||
|
||||
class User:
|
||||
def __init__(self, user_socket: network.socket):
|
||||
self.socket = user_socket
|
||||
self.connection, self.address = user_socket.accept()
|
||||
self.selector = selectors.DefaultSelector()
|
||||
|
||||
print("Accepted connection from", self.address)
|
||||
self.connection.setblocking(False)
|
||||
|
||||
def close(self):
|
||||
self.selector.close()
|
||||
self.socket.close()
|
||||
|
||||
def read(self):
|
||||
try:
|
||||
# Should be ready to read
|
||||
data = self.socket.recv(4096)
|
||||
except BlockingIOError:
|
||||
# Resource temporarily unavailable (errno EWOULDBLOCK)
|
||||
pass
|
||||
else:
|
||||
if data:
|
||||
print(message.deserialize(data))
|
||||
else:
|
||||
raise RuntimeError("Peer closed.")
|
||||
|
||||
def write(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
while True:
|
||||
events = self.selector.select(timeout=None)
|
||||
|
||||
for (key, mask) in events:
|
||||
try:
|
||||
if (mask & selectors.EVENT_READ):
|
||||
self.read()
|
||||
|
||||
elif (mask & selectors.EVENT_WRITE):
|
||||
self.write()
|
||||
|
||||
except Exception:
|
||||
print(f"Exception raised on {self.address}: {traceback.format_exc()}"),
|
||||
self.socket.close()
|
||||
|
||||
if not self.selector.get_map():
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("caught keyboard interrupt, exiting")
|
||||
|
||||
finally:
|
||||
self.selector.close()
|
||||
|
||||
def init():
|
||||
address = (config.host, config.port)
|
||||
selector = selectors.DefaultSelector()
|
||||
|
||||
with network.socket(network.AF_INET, network.SOCK_STREAM) as socket:
|
||||
# Avoid bind() exception: OSError: [Errno 48] Address already in use
|
||||
socket.setsockopt(network.SOL_SOCKET, network.SO_REUSEADDR, 1)
|
||||
socket.bind(address)
|
||||
socket.listen()
|
||||
|
||||
print("Listening on", address)
|
||||
|
||||
socket.setblocking(False)
|
||||
selector.register(socket, selectors.EVENT_READ, data=None)
|
||||
|
||||
users = []
|
||||
|
||||
try:
|
||||
while True:
|
||||
events = selector.select(timeout=None)
|
||||
|
||||
for (key, mask) in events:
|
||||
if key.data is None:
|
||||
user = User(key.fileobj)
|
||||
|
||||
users.append(user)
|
||||
user.run()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Caught keyboard interrupt, exiting")
|
||||
|
||||
finally:
|
||||
for user in users:
|
||||
user.close()
|
||||
|
||||
selector.close()
|
||||
|
||||
init()
|
Loading…
Reference in New Issue