Add simple networking module and test

This commit is contained in:
Guilherme Aleixo de Oliveira Martins 2024-11-29 11:39:53 -03:00
parent 276b090cfd
commit 055e4fa224
3 changed files with 154 additions and 0 deletions

View File

View File

@ -0,0 +1,130 @@
import socket, threading
class Networking:
"""
A class that contains common networking functions for both server and client.
"""
@staticmethod
def recv_any_size(sock):
"""
Receives data from the socket without knowing the size of the data.
The sender must send the size of the data before sending the data.
"""
data_size = sock.recv(1024).decode()
sock.send("OK".encode())
data = sock.recv(int(data_size)).decode()
return data
@staticmethod
def send_any_size(sock, data):
"""
Sends data to the socket without knowing the size of the data.
Sends the size of the data before sending the data.
"""
sock.send(str(len(data)).encode())
response = sock.recv(1024).decode()
sock.send(data.encode())
def recv_any_size(self, client):
"""
Receives data from the client without knowing the size of the data.
Client must send the size of the data before sending the data.
"""
data_size = client.recv(1024).decode()
data = client.recv(int(data_size)).decode()
return data
class Server:
"""
A basic server class that can be inherited to create a custom server.
Contains some basic networking functions.
"""
def __init__(self, host = "127.0.0.1", port = 8080):
"""
Hosts a basic server on the specified host and port
"""
self.host = host
self.port = port
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((self.host, self.port))
def start(self, max_connections = 5):
"""
Starts the server and listens for *max_connections* connections, defaulted to 5
"""
self.server.listen(max_connections)
while True:
client, addr = self.server.accept()
print(f"Connection from {addr}")
# Start a new thread for the client
threading.Thread(target=self.handle_client, args=(client,)).start()
def handle_client(self, client):
"""
Checks if the client sent "exit" and closes the connection if it did, else send the data back.
Overwrite with your own implementation.
"""
while True:
data = self.recv(client)
if data == "exit":
break
self.send(client, data)
pass
def send(self, client, data):
"""
Sends data to the client
"""
Networking.send_any_size(client, data)
def recv(self, client):
"""
Receives data from the client
"""
return Networking.recv_any_size(client)
def stop(self):
"""
Stops the server
"""
self.server.close()
class Client:
"""
A basic client class that can be inherited to create a custom client.
Contains some basic networking functions.
"""
def __init__(self, host = "127.0.0.1", port = 8080):
"""
Connects to a server on the specified host and port
"""
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.port))
def send(self, data):
"""
Sends data to the server
"""
Networking.send_any_size(self.sock, data)
def recv(self):
"""
Receives data from the server
"""
return Networking.recv_any_size(self.sock)
def close(self):
"""
Closes the connection
"""
Networking.send_any_size(self.sock, "exit")
self.sock.close()

24
src/test_networking.py Normal file
View File

@ -0,0 +1,24 @@
from networking import net_module
import socket, threading
class Test_server(net_module.Server):
def handle_client(self, client: socket.socket):
print(self.recv(client))
self.send(client, "Hello World")
print(self.recv(client))
client.close()
class Test_client(net_module.Client):
def main(self):
self.send("Hello World")
print(self.recv())
self.close()
server = Test_server()
threading.Thread(target=server.start, args=(1,)).start()
client = Test_client()
client.main()