Skip to content

Instantly share code, notes, and snippets.

@vrbadev
Created August 20, 2024 08:49
Show Gist options
  • Save vrbadev/9deecb9b5b66e6eb6604b57135ea2edd to your computer and use it in GitHub Desktop.
Save vrbadev/9deecb9b5b66e6eb6604b57135ea2edd to your computer and use it in GitHub Desktop.
Simple Python socket server echoing all messages back to connected clients, keeping track of closed client threads
# -*- coding: utf-8 -*-
"""
Created on Tue Aug 20 09:14:55 2024
@author: Vojtech Vrba ([email protected])
Simple socket client.
Connects to a server with an IP given by the current SSH connection, and with a port 12345.
Sends a sample message every 1 second and prints the server's response.
"""
import socket
import signal
import os
import time
import datetime
def format_time_addr(addr):
return "[%s|%s:%d]" % (datetime.datetime.now().strftime("%d.%m.%YT%H:%M:%S.%f"), addr[0], addr[1])
def is_socket_closed(sock):
try:
# this will try to read bytes without blocking and also without removing them from buffer (peek only)
data = sock.recv(16, socket.MSG_DONTWAIT | socket.MSG_PEEK)
if len(data) == 0:
return True
except BlockingIOError:
return False # socket is open and reading from it would block
except ConnectionResetError:
return True # socket was closed for some other reason
except Exception as e:
print("unexpected exception when checking if a socket is closed:", e)
return False
return False
if __name__ == "__main__":
print("Starting socket client")
terminated = False
signal.signal(signal.SIGINT, lambda sig, frame: globals().update(terminated=True))
ssh_ip = str(os.popen("echo $SSH_CONNECTION | awk '{print $1}'").read()).strip()
print("Server IP:", ssh_ip)
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((ssh_ip, 12345))
addr = client.getsockname()
print(format_time_addr(addr), "Connected to the server")
while not terminated and not is_socket_closed(client):
client.send("Hello world!".encode("ascii"))
rxdata = client.recv(1024)
print(format_time_addr(addr), "Received: ", rxdata)
time.sleep(1)
print(format_time_addr(addr), "Stopping socket client")
client.close()
print("Script done.")
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Aug 20 09:14:55 2024
@author: Vojtech Vrba ([email protected])
Simple socket server with threading support.
Listens at 0.0.0.0 (all interfaces) at port 12345.
Messages are only echoed back to clients.
"""
import socket
import threading
import signal
import datetime
def format_time_addr(addr):
return "[%s|%s:%d]" % (datetime.datetime.now().strftime("%d.%m.%YT%H:%M:%S.%f"), addr[0], addr[1])
class SocketClientThread(threading.Thread):
def __init__(self, client_socket, addr):
threading.Thread.__init__(self)
self.socket = client_socket
self.address = addr
self.terminated = threading.Event()
def run(self):
while not self.terminated.is_set() and not self.is_disconnected():
rxdata = self.socket.recv(1024)
if rxdata:
print(format_time_addr(self.address), "Received:", rxdata)
self.socket.send(b"Echo of: " + rxdata)
self.socket.close()
def is_disconnected(self):
try:
data = self.socket.recv(16, socket.MSG_DONTWAIT | socket.MSG_PEEK)
if len(data) == 0:
return True
except BlockingIOError:
return False # socket is open and reading from it would block
except ConnectionResetError:
return True # socket was closed for some other reason
except Exception as e:
print(format_time_addr(self.address), "unexpected exception when checking if a socket is closed:", e)
return False
def terminate(self):
self.terminated.set()
if __name__ == "__main__":
print("Starting socket server script")
terminated = False
signal.signal(signal.SIGINT, lambda sig, frame: globals().update(terminated=True))
print("Initializing server socket")
server_addr = ("0.0.0.0", 12345)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.settimeout(0.1)
server.bind(server_addr)
server.listen(1)
print(format_time_addr(server_addr), "Server is waiting for new connections...")
client_threads = dict()
while not terminated:
try:
client, addr = server.accept()
print(format_time_addr(addr), "Connection opened")
t = SocketClientThread(client, addr)
client_threads[addr] = t
t.start()
except socket.timeout:
pass
except:
raise
closed = list()
for a, t in client_threads.items():
if not t.is_alive():
print(format_time_addr(addr), "Connection closed")
closed.append(a)
for a in closed: client_threads.pop(a)
print(format_time_addr(server_addr), "Server closing...")
for a, t in client_threads.items():
if t.is_alive():
t.terminate()
t.join()
server.close()
print("Script done.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment