Netbits server Tutorial¶
This tutorial will guide you through creating a Python server that uses custom structured packets to communicate with clients using the netbits library. We will define two types of packets: ExampleRequest and StringMessage, and implement a server to handle these packets.
The complete source code can be found on GitHub.
Requirements¶
Before you start, ensure you have the netbits library installed. You can install it using pip:
pip install netbits
Packet Classes¶
We will define two packet classes: ExampleRequest and StringMessage.
ExampleRequest Packet¶
The ExampleRequest packet contains the following fields:
title (string)
x (integer)
y (integer)
width (integer)
height (integer)
from netbits.packet import StructuredPacket
class ExampleRequest(StructuredPacket):
def __init__(self, title: str, x: int, y: int, width: int, height: int):
super().__init__()
self.title = title
self.x = x
self.y = y
self.width = width
self.height = height
def pack(self, buffer):
buffer.write_string(self.title)
buffer.write_int(self.x)
buffer.write_int(self.y)
buffer.write_int(self.width)
buffer.write_int(self.height)
@classmethod
def unpack(cls, buffer):
return cls(buffer.read_string(), buffer.read_int(), buffer.read_int(), buffer.read_int(), buffer.read_int())
StringMessage Packet¶
The StringMessage packet contains a single field:
string (string)
class StringMessage(StructuredPacket):
def __init__(self, string: str):
super().__init__()
self.string = string
def pack(self, buffer):
buffer.write_string(self.string)
@classmethod
def unpack(cls, buffer):
return cls(buffer.read_string())
Registry and Message Handler¶
Next, we will set up a registry and a message handler to process the incoming packets.
Registry Setup¶
from netbits.registries import *
from typing import Type
reg = Registry[Type[StructuredPacket]]()
reg.register(Identifier.from_string("example:request"), ExampleRequest)
reg.register(Identifier.from_string("example:string_message"), StringMessage)
Message Handler¶
from netbits.handler import MessageHandler, handlesMessage
class ServerMessageHandler(MessageHandler):
def __init__(self):
super().__init__()
@handlesMessage(ExampleRequest)
def handle_example_request(self, message: StructuredPacket, user_data):
print(f"Got Example Request: {vars(message)} with user data: {user_data}")
@handlesMessage(StringMessage)
def handle_string_message(self, message: StructuredPacket, user_data):
global reg
print(f"Got String Message: {vars(message)} with user data: {user_data}")
sendStructuredPacket(user_data[0], StringMessage("I'm sorry"), reg)
Client Handler¶
We will create a function to handle new client connections.
import socket
from netbits.sockets import *
def on_new_client(client_socket: socket.socket, addr: str):
global reg
sh = ServerMessageHandler()
while True:
message = readStructuredPacket(client_socket, reg)
if message is None:
break
sh.handle(message, (client_socket, addr))
Server Implementation¶
Finally, we will implement the server to accept connections and handle client messages in separate threads.
from threading import Thread
def socket_main():
host = '0.0.0.0'
port = 8888
s = socket.socket()
s.bind((host, port))
s.listen(5)
print(f"Listening on {host}:{port}")
while True:
c, addr = s.accept()
print(f"New connection from: {addr}")
thread = Thread(target=on_new_client, args=(c, addr), daemon=True)
thread.start()
if __name__ == '__main__':
socket_main()
Explanation¶
- Packet Definition:
ExampleRequest and StringMessage classes are defined, inheriting from StructuredPacket.
Both classes implement the pack and unpack methods to serialize and deserialize packet data.
- Registry Initialization:
A registry for packet types is created and packet classes are registered with unique identifiers. The registry must have the same keys and values as the client!
- Message Handler:
ServerMessageHandler class is defined to handle incoming packets using the handle_example_request and handle_string_message methods.
- Client Handler:
The on_new_client function reads incoming packets from the client and passes them to the message handler.
- Server Setup:
A socket is created to listen for incoming connections on port 8888.
For each new connection, a new thread is spawned to handle client messages.
Conclusion¶
This tutorial covers the basics of creating and using custom structured packets in Python with the netbits library. You can expand this example by adding more packet types and handling additional message types.