i think mio would still be good here

This commit is contained in:
2024-04-18 20:08:08 +02:00
parent c510df3154
commit 7d51c2813d
7 changed files with 152 additions and 80 deletions

View File

@ -1,4 +1,6 @@
from typing import Any, Optional
import select
import time
import socket
import logging
from threading import Thread, Event, Lock
@ -16,6 +18,7 @@ class TcpServer(ComInterface):
self.port = port
self._max_num_packets_in_tc_queue = 500
self._max_num_packets_in_tm_queue = 500
self._default_timeout_secs = 0.5
self._server_addr = ("localhost", self.port)
self._tc_packet_queue = deque()
self._tm_packet_queue = deque()
@ -23,8 +26,11 @@ class TcpServer(ComInterface):
self._tm_lock = Lock()
self._kill_signal = Event()
self._server_socket: Optional[socket.socket] = None
self._server_thread = Thread(target=TcpServer._server_task, daemon=True)
self._server_thread = Thread(target=self._server_task, daemon=True)
self._connected = False
self._conn_start = None
self._writing_done = False
self._reading_done = False
@property
def connected(self) -> bool:
@ -47,31 +53,44 @@ class TcpServer(ComInterface):
"""
if self.connected:
return
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# We need to check the kill signal periodically to allow closing the server.
self.server_socket.settimeout(0.5)
self.server_socket.bind(self._server_addr)
self._connected = True
self._server_thread.start()
def _server_task(self):
assert self._server_socket is not None
self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# We need to check the kill signal periodically to allow closing the server.
self._server_socket.settimeout(self._default_timeout_secs)
self._server_socket.bind(self._server_addr)
self._server_socket.listen()
while True and not self._kill_signal.is_set():
self._server_socket.listen()
(conn_socket, conn_addr) = self._server_socket.accept()
_LOGGER.info("TCP client {} connected", conn_addr)
while True:
bytes_recvd = conn_socket.recv(4096)
if len(bytes_recvd) > 0:
print(f"Received bytes from TCP client: {bytes_recvd.decode()}")
with self._tm_lock:
self._tm_packet_queue.append(bytes_recvd)
elif len(bytes_recvd) == 0:
break
else:
print("error receiving data from TCP client")
try:
(conn_socket, conn_addr) = self._server_socket.accept()
self.conn_start = time.time()
while True:
self._handle_connection(conn_socket, conn_addr)
if (
self._reading_done and self._writing_done
) or time.time() - self.conn_start > 0.5:
print("reading and writing done")
break
except TimeoutError:
print("timeout error")
continue
def _handle_connection(self, conn_socket: socket.socket, conn_addr: Any):
_LOGGER.info(f"TCP client {conn_addr} connected")
(readable, writable, _) = select.select(
[conn_socket],
[conn_socket],
[],
0.1,
)
# TODO: Why is the stupid conn socket never readable?
print(f"Writable: {writable}")
print(f"Readable: {readable}")
if writable and writable[0]:
queue_len = 0
with self._tc_lock:
queue_len = len(self._tc_packet_queue)
@ -79,8 +98,23 @@ class TcpServer(ComInterface):
next_packet = bytes()
with self._tc_lock:
next_packet = self._tc_packet_queue.popleft()
conn_socket.sendall(next_packet)
if len(next_packet) > 0:
conn_socket.sendall(next_packet)
queue_len -= 1
self._writing_done = True
if readable and readable[0]:
print("reading shit")
while True:
bytes_recvd = conn_socket.recv(4096)
if len(bytes_recvd) > 0:
print(f"Received bytes from TCP client: {bytes_recvd.decode()}")
with self._tm_lock:
self._tm_packet_queue.append(bytes_recvd)
elif len(bytes_recvd) == 0:
self._reading_done = True
break
else:
print("error receiving data from TCP client")
def is_open(self) -> bool:
"""Can be used to check whether the communication interface is open. This is useful if
@ -103,7 +137,6 @@ class TcpServer(ComInterface):
:raises SendError: Sending failed for some reason.
"""
with self._tc_lock:
# Deque is thread-safe according to the documentation.. so this should be fine.
if len(self._tc_packet_queue) >= self._max_num_packets_in_tc_queue:
# Remove oldest packet
self._tc_packet_queue.popleft()