I have checked the documentation online and several Stackoverflow posts, but cannot debug my code. I think I am incorrectly sending bytes, so the other nodes connected to the socket cannot 'hear' the calls.
Is there something wrong with my use of sendall(), or something wrong with how I'm packing my bytestring?
import logging
from random import randint
import socket
import sys
import time
import threading
class Server:
connections = list()
peers = list()
def __init__(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 10000))
s.listen(1)
logging.info('Successfully started the server on port 10000.')
while True:
c, a = s.accept()
logging.info('New client node joins pool.')
t = threading.Thread(target=self.handler, args=(c, a))
t.daemon = True
t.start()
self.connections.append(c)
self.peers.append(a[0])
logging.info('New node connected: {}'.format(str(a[0])))
self.send_peers()
def handler(self, c, a):
while True:
data = c.recv(1024)
logging.info('Sending data: {}'.format(data))
for connection in self.connections:
connection.sendall(data)
if not data:
logging.info('Node disconnected: {}:{}'.format(str(a[0]), str(a[1])))
self.connections.remove(c)
self.peers.remove(a[0])
c.close()
self.send_peers()
break
def send_peers(self):
"""Sends the list of peers in the swarm to all connected peers."""
p = ''
for peer in self.peers:
p = p + peer + ','
for connection in self.connections:
connection.sendall(b'\x11' + p.encode())
class Client:
def __init__(self, address):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect((address, 10000))
logging.info('Successfully made a client connection at: {}. Listening..'.format(address))
t = threading.Thread(target=self.send_message, args=(s,))
t.daemon = True
t.start()
while True:
data = s.recv(1024)
print(data)
if not data:
break
if data[0:1] == b'\x11':
# Message prefixed with \x11, so we know it is a new node message
self.update_peers(data[1:])
else:
# Since the message received isn't prefixed with \x11, we know it is a message
logging.info('Received message: {}'.format(data.decode()))
#staticmethod
def send_message(s):
"""Sends a message to all connected nodes."""
while True:
message = str(input('Enter message: ')).encode()
s.sendall(message)
logging.info('Sending message: {}'.format(message.decode()))
#staticmethod
def update_peers(peer_data):
"""Refreshes the local copy of all connected nodes."""
logging.info('Node dropped/connected. Updating connected peers list.')
Tracker.peers = peer_data.decode.split(',')[:-1]
class Tracker:
"""Tracks the Peers connected within the swarm.
This is a separate class due to data accessibility. We want to be able to access the peers list
from outside the Client and Server classes.
"""
peers = ['127.0.0.1']
if __name__ == '__main__':
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S')
logging.info('Connecting..')
while True:
try:
time.sleep(randint(1, 5))
for peer in Tracker.peers:
try:
server = Server()
except KeyboardInterrupt:
sys.exit(0)
except:
logging.warning('Server is already started. Becoming a client node.')
try:
client = Client(peer)
except KeyboardInterrupt:
sys.exit(0)
except:
logging.warning('Could not become a client node.')
pass
except KeyboardInterrupt:
sys.exit(0)
Related
I am attempting to piece together a secure socket client server communication solution. I do not have experience in doing so, so have cobbled together what I believe are relevant sections. The idea is that the Server waits for connections, the client creates a connection that is secure and then communication can take place.
The code also utilizes secure communication in authorization with client and server keys and certificates.
client code:
class Client:
def __init__(self):
try:
self.host, self.port = "127.0.0.1", 65416
self.client_cert = os.path.join(os.path.dirname(__file__), "client.crt")
self.client_key = os.path.join(os.path.dirname(__file__), "client.key")
self._context = ssl.SSLContext()
self._context.load_cert_chain(self.client_cert, self.client_key)
self._sock = None
self._ssock = None
except Exception as e:
print("Error in Initializing")
def checkvalidclient(self):
# ---- Client Communication Setup ----
HOST = self.host # The server's hostname or IP address
PORT = self.port # The port used by the server
try:
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._ssock = self._context.wrap_socket(self._sock,)
self._ssock.connect((HOST, PORT))
print ("Socket successfully created")
except socket.error as err:
print ("socket creation failed with error %s" %(err))
print('Waiting for connection')
Response = self._ssock.recv(1024)
while True:
Input = input('Say Something: ')
# s.send(str.encode(Input))
send_msg(self._ssock, str.encode(Input))
# Response = s.recv(1024)
Response = recv_msg(self._ssock)
if Response is not None:
print(Response.decode('utf-8'))
def closesockconnection(self):
self._ssock.close()
# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg): # ---- Use this to send
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock: socket): # ---- Use this to receive
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock: socket, n: int):
# Helper function to receive n bytes or return None if EOF is hit
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return data
client = Client()
client.checkvalidclient()
Server code:
import socket
import os
import ssl
from os import path
from _thread import *
import struct # Here to convert Python data types into byte streams (in string) and back
# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg): # ---- Use this to send
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock: socket): # ---- Use this to receive
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock: socket, n: int):
# Helper function to receive n bytes or return None if EOF is hit
try:
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return data
except Exception as e:
print("Exception in recvall : " + str(e))
# ---- Server Communication Setup
class Server:
def __init__(self):
self.HOST = '127.0.0.1' # Standard loopback interface address (localhost)
self.PORT = 65416 # Port to listen on (non-privileged ports are > 1023)
self.ThreadCount = 0
self.server_cert = path.join(path.dirname(__file__), "server.crt")
self.server_key = path.join(path.dirname(__file__), "server.key")
self.client_cert = path.join(path.dirname(__file__), "client.crt")
self._context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self._context.verify_mode = ssl.CERT_REQUIRED
self._context.load_cert_chain(self.server_cert, self.server_key)
self._context.load_verify_locations(self.client_cert)
self.sock = None
def connect(self):
try: # create socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
print ("Socket successfully created")
except socket.error as err:
print ("socket creation failed with error %s" %(err))
try: # bind socket to an address
self.sock.bind((self.HOST, self.PORT))
except socket.error as e:
print(str(e))
print('Waiting for a Connection..')
self.sock.listen(3)
def threaded_client(self, conn: socket):
conn.send(str.encode('Welcome to the Server'))
while True:
# data = conn.recv(2048) # receive message from client
data = recv_msg(conn)
print(data)
if data is not None:
reply = 'Server Says: ' + data.decode('utf-8')
if not data:
break
# conn.sendall(str.encode(reply))
send_msg(conn, str.encode(reply))
#conn.close()
def waitforconnection(self):
while True:
Client, addr = self.sock.accept()
self._context.wrap_socket(Client, server_side=True)
print('Connected to: ' + addr[0] + ':' + str(addr[1]))
start_new_thread(self.threaded_client, (Client, )) # Calling threaded_client() on a new thread
self.ThreadCount += 1
print('Thread Number: ' + str(self.ThreadCount))
#self.sock.close()
server = Server()
server.connect()
server.waitforconnection()
The lines:
def threaded_client(self, conn: socket):
conn.send(str.encode('Welcome to the Server'))
result in the error:
[WinError 10038] An operation was attempted on something that is not a socket
When I removed the certificate related lines in client:
self.client_cert = os.path.join(os.path.dirname(__file__), "client.crt")
self.client_key = os.path.join(os.path.dirname(__file__), "client.key")
self._context = ssl.SSLContext()
self._context.load_cert_chain(self.client_cert, self.client_key)
and the certificate related lines in the server:
self.server_cert = path.join(path.dirname(__file__), "server.crt")
self.server_key = path.join(path.dirname(__file__), "server.key")
self.client_cert = path.join(path.dirname(__file__), "client.crt")
self._context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self._context.verify_mode = ssl.CERT_REQUIRED
self._context.load_cert_chain(self.server_cert, self.server_key)
self._context.load_verify_locations(self.client_cert)
self.sock = None
and a couple of small changes to remove the certificate related functionality, everything seemed to work, the client could send messages to the server and the server could respond (and the client displayed the response).
When however I added the context related certificates I start getting the error:
An operation was attempted on something that is not a socket
The server waits at:
Client, addr = self.sock.accept()
and continues to run once the client has called (in the client.py file):
self._ssock.connect((HOST, PORT))
The server then reaches the lines:
def threaded_client(self, conn: socket):
conn.send(str.encode('Welcome to the Server'))
where it fails on this error.
Printing the terminal, a traceback and exception error results in:
Socket successfully created
Waiting for a Connection..
Connected to: 127.0.0.1:57434
Thread Number: 1
Traceback (most recent call last):
File "c:\testcode\Server.py", line 71, in threaded_client
conn.send(str.encode('Welcome to the Server'))
OSError: [WinError 10038] An operation was attempted on something that is not a socket
My knowledge is limited and I cannot find more examples of secure multi threaded two way communication client to server socket code. The idea is to ensure the client is authorized to communicate with the server before transmission happens.
Any ideas on where I am failing?
Thanks
Ok, It seems like I was close, but had a couple of tweaks to do.
The solution of:
SSL/TLS client certificate verification with Python v3.4+ SSLContext
and the commenters here, helped me get over the finish line.
Server code:
import socket
import os
from socket import AF_INET, SOCK_STREAM, SO_REUSEADDR, SOL_SOCKET, SHUT_RDWR
import ssl
from os import path
from _thread import *
import struct # Here to convert Python data types into byte streams (in string) and back
import traceback
# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg): # ---- Use this to send
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock: socket): # ---- Use this to receive
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock: socket, n: int):
# Helper function to receive n bytes or return None if EOF is hit
try:
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return data
except Exception as e:
print("Exception in recvall : " + str(e))
# ---- Server Communication Setup
class Server:
def __init__(self):
self.HOST = '127.0.0.1' # Standard loopback interface address (localhost)
self.PORT = 65416 # Port to listen on (non-privileged ports are > 1023)
self.ThreadCount = 0
self.server_cert = path.join(path.dirname(__file__), "server.crt")
self.server_key = path.join(path.dirname(__file__), "server.key")
self.client_cert = path.join(path.dirname(__file__), "client.crt")
self._context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
self._context.verify_mode = ssl.CERT_REQUIRED
self._context.load_cert_chain(certfile=self.server_cert, keyfile=self.server_key)
self._context.load_verify_locations(cafile=self.client_cert)
self.sock = None
def connect(self):
try: # create socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) ###<-- socket.socket() ???
print ("Socket successfully created")
except socket.error as err:
print ("socket creation failed with error %s" %(err))
try: # bind socket to an address
self.sock.bind((self.HOST, self.PORT))
except socket.error as e:
print(str(e))
print('Waiting for a Connection..')
self.sock.listen(3)
def threaded_client(self, conn: socket):
try:
conn.send(str.encode('Welcome to the Server'))
while True:
data = recv_msg(conn)
print("data")
print(data)
if data is not None:
reply = 'Server Says: ' + data.decode('utf-8')
if not data:
break
send_msg(conn, str.encode(reply))
except Exception as e:
print(traceback.format_exc())
print(str(e))
finally:
print("Closing connection")
conn.shutdown(socket.SHUT_RDWR)
conn.close()
#conn.close()
def waitforconnection(self):
while True:
Client, addr = self.sock.accept()
conn = self._context.wrap_socket(Client, server_side=True)
print('Connected to: ' + addr[0] + ':' + str(addr[1]))
print("SSL established. Peer: {}".format(conn.getpeercert()))
start_new_thread(self.threaded_client, (conn, )) # Calling threaded_client() on a new thread
self.ThreadCount += 1
print('Thread Number: ' + str(self.ThreadCount))
#self.sock.close()
server = Server()
server.connect()
server.waitforconnection()
Client code:
import socket
import struct # Here to convert Python data types into byte streams (in string) and back
import sys
import ssl
import socket
import selectors
import types
import io
import os
import time
import requests
from pathlib import Path
import mysql.connector as mysql
from loguru import logger as log
from utils.misc import read_py_config
import json
import rsa
import base64
class Client:
def __init__(self):
self.host, self.port = "127.0.0.1", 65416
self.client_cert = os.path.join(os.path.dirname(__file__), "client.crt")
self.client_key = os.path.join(os.path.dirname(__file__), "client.key")
self.server_crt = os.path.join(os.path.dirname(__file__), "server.crt")
self.sni_hostname = "example.com"
self._context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=self.server_crt)
self._context.load_cert_chain(certfile=self.client_cert, keyfile=self.client_key)
self._sock = None
self._ssock = None
def checkvalidclient(self):
# ---- Client Communication Setup ----
HOST = self.host # The server's hostname or IP address
PORT = self.port # The port used by the server
try:
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._ssock = self._context.wrap_socket(self._sock, server_side=False, server_hostname=self.sni_hostname)
self._ssock.connect((HOST, PORT))
print ("Socket successfully created")
except socket.error as err:
print ("socket creation failed with error %s" %(err))
print('Waiting for connection')
Response = self._ssock.recv(1024)
if Response is not None:
print(Response.decode('utf-8'))
while True:
Input = input('Say Something: ')
send_msg(self._ssock, str.encode(Input))
Response = recv_msg(self._ssock)
if Response is not None:
print(Response.decode('utf-8'))
def closesockconnection(self):
self._ssock.close()
# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg): # ---- Use this to send
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock: socket): # ---- Use this to receive
# Read message length and unpack it into an integer
raw_msglen = recvall(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return recvall(sock, msglen)
def recvall(sock: socket, n: int):
# Helper function to receive n bytes or return None if EOF is hit
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return data
Also ensure (as per the link) that the certificate creation is correct.
There is also another useful link at:
Exploring HTTPS With Python
Which covers HTTPS, specifically the Wireshark section allows you to monitor the traffic from client to server. After completing the above and deploying Wireshark I see that the data is encrypted. Any editing of the certificates (manually) causes the app to fail.
There still needs to be additions of try and except if the communication is halted midway etc. But hoping it will smooth the journey for others.
Thanks to the commenters, helped lead me on the way to solution.
I am trying to create a function to send and receive information over a socket client & server. It appears that my code is somehow blocking. In the code the first command iteration in my for loop is carried out but then the process becomes blocked. Does anyone have any suggestions how to do this using threading or multithreading?
My code is below:
import socket
import json
import sys
import time
import select
import queue
Ni_Rio_IP= "172.22.11.2"
Ni_Base_IP= "172.22.11.1"
class AliceRio:
def __init__(self, ip_rio, ip_pc):
self.ip_rio = ip_rio
AliceRio.udp_port_rio = 60006
self.ip_pc = ip_pc
AliceRio.udp_port_pc = 50005
AliceRio.json= '{"Dest":"","Name":"","Time":"","Val":{"Str":[],"Pos":[[]],"Data":[[]]},"IP":0,"Port":0,"RT error":{"status":false,"code":0,"source":""}}'
AliceRio.dict= json.loads(self.json)
def PrintUDP(self):
print("RIO IP: %s" % self.ip_rio)
print("RIO UDP port: %s" % self.udp_port_rio)
print("PC IP: %s" % self.ip_pc)
print("PC UDP port: %s" % self.udp_port_pc)
def SendRec(self, send_str):
# Set up socket for sending
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet, UDP
sock.sendto(bytes(send_str, 'utf-8'), (self.ip_rio, self.udp_port_rio))
sock.close()
print('got here')
# Set up socket for receiving
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Internet, UDP
sock.bind((self.ip_pc, self.udp_port_pc))
rec_str, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print('got here2')
sock.close()
return rec_str
def Receive(self, rec_str):
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Internet, UDP
sock.bind((self.ip_pc, self.udp_port_pc))
rec_str, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
sock.close()
return rec_str
def Send(self, send_str):
# Set up socket for sending
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet, UDP
sock.sendto(bytes(send_str, 'utf-8'), (self.ip_rio, self.udp_port_rio))
sock.close()
#return rec_str
def Aim(self, aim_perc):
if aim_perc < 0 or aim_perc > 100: return "aim_perc out of range"
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='Laser Control'
Laser_Mode=1
Simmer_A=0
Pulse_A= 0
Pulse_ms= 20
send_dict["Val"]["Str"]=[str(Laser_Mode), str(aim_perc), str(Simmer_A), str(Pulse_A), str(Pulse_ms)]
send_json=json.dumps(send_dict)
# send it out
self.SendRec(send_json)
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
return "Aim laser now at " + rec_dict["Val"]["Str"][1] +'%'
def PWM_Laser_Fan(self, fan_perc):
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='PWM Laser'
send_dict["Val"]["Str"][0]=str(fan_perc)
send_json=json.dumps(send_dict)
# send it out
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
return rec_dict["Val"]["Str"][0]
def Poll(self):
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='Poll'
send_json=json.dumps(send_dict)
# send it out
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
if rec_dict["Val"]["Data"][0][0]==0: pid_mode='off'
else: pid_mode='PID'
print('PID mode:', pid_mode)
print('Pos X:', rec_dict["Val"]["Data"][0][1])
print('Pos Y:', rec_dict["Val"]["Data"][0][2])
print('Home:', rec_dict["Val"]["Data"][0][3])
print('Enabled:', rec_dict["Val"]["Data"][0][4])
def PIDControl(self, pid_mode,pid_center):
if pid_mode=="off": mode= 0
elif pid_mode=="PID":mode =1
else: return "pid_mode not valid"
if pid_center[0] not in range(-2048,2048): return "center x-pos not in range"
if pid_center[1] not in range(-2048,2048): return "center y-pos not in range"
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='PID Control'
send_dict["Val"]["Str"]=[str(mode), str(pid_center[0]), str(pid_center[1])]
send_json=json.dumps(send_dict)
# send it out
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
return "PID mode now at " + rec_dict["Val"]["Str"][0]
Alice1 = AliceRio(Ni_Rio_IP, Ni_Base_IP)
Alice1.PrintUDP()
for i in range(10):
Alice1.Aim((i*10)+10)
time.sleep(0.2)
I would suggest learning to use Pdb and trace through the execution of your program to find where it is getting caught.
Also when learning/developing with sockets I've found that it helps to have separate programs for your client and server in the beginning so you can see how both sides are handling exchanges instead of going the threading route to start since the logging can get confusing, best of luck!
Module threading does help in this scenario.
We can create a thread to receiving incoming messages. And when new message received the thread trigger an event to notify the waiting method SendRec.
import sys
import socket
import json
import threading
import time
class AliceRio:
def __init__(self, .....):
# .........
self.s_in = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s_in.bind((self.ip_pc, self.udp_port_pc))
self.evt = threading.Event()
self.last_msg = None
def _recv(self):
while True:
msg, _ = self.s_in.recvfrom(1024)
self.last_msg = msg
self.evt.set()
def SendRec(self, send_str):
if not hasattr(self, 'th_recv'):
th = threading.Thread(target=self._recv)
th.setDaemon(True)
th.start()
self.th_recv = th
self.evt.clear()
rio_endpoint = (self.ip_rio, self.udp_port_rio)
s_out = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s_out.sendto(bytes(send_str, 'utf-8'), rio_endpoint)
s_out.close()
if self.evt.wait(timeout=15.0) and self.last_msg:
return self.last_msg
raise Exception('timeout waiting for response.')
I'm trying to make a small multiplayer game and thus need to send objects. Have created server and client and everything is working for sending bytes e.g. (str("").encode(utf-8)).
But when I tried to use pickle I've started bumping into issues. Have I made any mistakes below?
Server.py:
import socket
import threading
import pickle
HEADER = 8 #Contains info about incoming msg SIZE! first 8 bytes contains size
FORMAT = "utf-8"
PORT = 5558
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
DISCONNECT_MSG = "!Disconnect"
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(ADDR)
def handle_client(client_socket, client_addr):
print(f"[NEW CONNECTION] {client_addr} connected!")
while True:
try:
msg = pickle.loads(client_socket.recv(2048))
print(f"[RECEIVED] {client_addr} - {msg}")
if msg == DISCONNECT_MSG:
print(f"[DISCONNECTED] client {client_addr} has disconnected")
client_socket.close()
return False
except socket.error as e:
print(e)
def start_server(server):
server.listen()
print("[STARTED] server is online!")
while True:
client_socket, client_addr = server.accept()
thread = threading.Thread(target=handle_client, args=(client_socket, client_addr))
thread.start()
print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")
print("[STARTING] server is starting...")
start_server(server_socket)
Client.py
import socket
import pickle
HEADER = 8
FORMAT = "utf-8"
PORT = 5558
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
DISCONNECT_MSG = "!Disconnect"
class Client:
def __init__(self):
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def connect_to_server(self, server_address):
"""
:param server_address: tuple(IP, PORT)
:return:
"""
self.get_client_socket().connect(server_address)
def get_client_socket(self):
return self.client_socket
def send_object(self, object):
msg = pickle.dumps(object)
self.get_client_socket().sendall(msg)
client = Client()
client.connect_to_server(ADDR)
d = "1"
client.send_object(d)
#client.send_object(DISCONNECT_MSG)
I've also tried to put while loop into send_object() but then after couple of successful receivements I get:
msg = pickle.loads(client_socket.recv(2048))
_pickle.UnpicklingError: invalid load key, '\x00'.
After some research it appears that before trying to unpickle an object you first need to check if received message is not None. Because server is constantly trying to receive message from client, but that is another issue.
Code modification in server.py:
def handle_client(client_socket, client_addr):
print(f"[NEW CONNECTION] {client_addr} connected!")
while True:
try:
msg = client_socket.recv(2048)
if msg:
new_msg = pickle.loads(msg[HEADER:])
print(f"[RECEIVED] {client_addr} - {new_msg}")
if msg == DISCONNECT_MSG:
print(f"[DISCONNECTED] client {client_addr} has disconnected")
client_socket.close()
return False
except socket.error as e:
print(e)
Note -> Until DISCONNECT message is not sent from client it will use much processor time (issue mentioned above)
Well, I'm trying to make a simple Network TCP chatting program to dive deeper in python, threading and networking. The program worked but with just one user, I looked this up, I found that I need threading to make the server accept more than one user. I threaded the server but now when you connect the second user it disconnect the first one. Source code may not be that good..
#!/usr/bin/python
import socket, sys, threading
from time import sleep
# Global Stuff
localhost = socket.gethostbyname(socket.gethostname())
#localhost = '192.168.x.x'
serverPort = 5003
buffer = 1024 #Bytes
backlog = 5
userThread= []
count = 0
class server(object):
''' Constructor to Establish Bind server once an object made'''
def __init__(self, localhost, serverPort): # Connect Tcp
global backlog, count
self.servSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.servSock.bind((localhost, serverPort))# bind((host,Port))
self.servSock.listen(backlog)
print count
except Exception, e:
print "[Bind ]", e
sys.exit()
def accept(self):
global userThread, conn, addr, count
"""
- PROBLEM IS IN HERE SOMEWHERE SERVER DOESN'T ADD THE OTHER CLIENT EXCEPT ONCE.
- THREAD DOEN'T KEEP THE CLIENT.
- THE SECOND CLIENT FREEZES WHILE SENDING THE VERY FIRST MESSAGE TILL THE FIRST
CLIENT SEND A MESSAGE THEN IT CAN SEND MESSAGES AND THE FIRST CLIENT CAN'T SEND SHIT.
"""
count+=1
while True:
print count
self.conn, self.addr = self.servSock.accept()
conn = self.conn
print("This is a connection: ", conn)
#acceptThread = threading.start_new_thread(target=serverObj.accept, args=(conn))
#addr = self.addr
print "[Listening..]"
if(self.addr not in userThread):
userThread.append(self.addr)
print "Client's added Successfully"
else:
pass
def redirect(self):
global buffer, userThread, conn, count
count+=1
while True:
try:
print "Redirecting " + str(count)
self.data = conn.recv(buffer)
if self.data:
for user in userThread:
#conn.send(b'Recieved by server!\n')
conn.sendto("Sent!\n"+self.data+"\n", user)
print "Server: Data sent[" +self.data+"] to ["+str(user)+"]"
else:
self.data = conn.recv(buffer)
print "No dataa found"
except Exception, e:
print "[Redirect ] ",e
sleep(7)
print "OUT"# testing if it's getting out this infinite loop.
def exit(self):
self.server.close()
def main():
global localhost, serverPort, conn
try:
serverObj = server(localhost, serverPort)
print("[+] Server is UP!")
except Exception, e:
print "[Main ] ",e
exit()
acceptThread = threading.Thread(name = "Accepting Connections", target=serverObj.accept)
redirThread = threading.Thread(name = "Redirecting Data", target=serverObj.redirect)
acceptThread.start()
redirThread.start()
print userThread
main()
######################################### Client ##########################################
#!/usr/bin/python
# This is client file
"""
http://eli.thegreenplace.net/2011/05/18/code-sample-socket-client-thread-in-python
https://docs.python.org/2/library/threading.html
"""
import socket
import threading
from time import sleep
# Client Info
#clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#localhost = '192.168.x.x'
# Global Stuff
serverIP = socket.gethostbyname(socket.gethostname())
#serverIP = '192.168.x.x'
serverPort, MsgSendError, MsgSendSucc, clientPort, data, buffer =\
5003, False, True, 12345, '',1024 #Bytes
class client(object):
global MsgSendError, MsgSendSucc, buffer, data
''' Constructor to Establish Connection once client is up'''
def __init__(self, serverIP, serverPort): # Connect Tcp
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.sock.connect((serverIP, serverPort))
except Exception, e:
return "[Connecting to Server]", e
def send(self, data):
try:
self.sock.send(data) # covnert it from string into byte streams to be in proper format.
#print str(data)
return MsgSendSucc
except:
return MsgSendError
def receive2(self):
try:
data = self.sock.recv(buffer)
#print "Function: Receive2."# testing
#print(str(data))# testing
#print "Received!"# testing
return str(data)
except Exception, e:
return "[In receive2]", e
def main():
global serverIP, serverPort, data#, sock
clientObj = client(serverIP, serverPort)
alias = raw_input("Your Name USER! ")
sentData = ''
while sentData is not 'Quit':
sentData = raw_input("Data>> ")
data = alias + ": "+sentData
if clientObj.send(data) == MsgSendSucc:
#print "Sent!"
#print "Fetching..\n"# testing
print(clientObj.receive2())
# testing
main()
I'm trying to create a small, multithreaded proxyscript that allows me to proxy LDAP requests and manipulate the results (like adding extra fields, renaming them etc).
In the example below, I try to replace the field 'TEST' by 'DONE'. Is there any solution to allow this socketstream to be manipulated? Should I decode it somewhat first?
import select
import socket
import sys
import threading
import signal
import re
import random
import time
import binascii
from ldaptor.protocols import pureldap, pureber
from time import gmtime, strftime
ASTLDAP_PROXY_PORT = 1389
ASTLDAP_HOST = 'localhost'
ASTLDAP_PORT = 389
BUFFERSIZE = 1024
DELAY = 0.0001
class Forward:
def __init__(self):
self.forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def start(self, host, port):
try:
self.forward.connect((host, port))
return self.forward
except Exception, e:
print e
return False
class AstLdapProxyServer(threading.Thread):
input_list = []
channel = {}
def __init__(self, host, port, socket):
threading.Thread.__init__(self)
self.host = host
self.port = port
# Socket ontvangen die we meekregen bij nieuwe thread.
self.socket = socket
print "[+] New thread started for "+host+":"+str(port)
self.socket.bind((host, port))
self.socket.listen(200)
def register_signals(self):
signal.signal(signal.SIGHUP, self.signal_handler)
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGQUIT, self.signal_handler)
def main_loop(self):
self.input_list.append(self.socket)
while 1:
#time.sleep(DELAY)
ss = select.select
inputready, outputready, exceptready = ss(self.input_list, [], [])
for self.s in inputready:
if self.s == self.socket:
self.on_accept()
break
self.data = self.s.recv(BUFFERSIZE)
if len(self.data) == 0:
self.on_close()
else:
self.on_recv()
def on_accept(self):
forward = Forward().start(ASTLDAP_HOST, ASTLDAP_PORT)
clientsock, clientaddr = self.socket.accept()
if forward:
print clientaddr, "has connected"
self.input_list.append(clientsock)
self.input_list.append(forward)
self.channel[clientsock] = forward
self.channel[forward] = clientsock
else:
print "Can't establish connection with remote server.",
print "Closing connection with client side", clientaddr
clientsock.close()
def on_close(self):
print self.s.getpeername(), "has disconnected"
#remove objects from input_list
self.input_list.remove(self.s)
self.input_list.remove(self.channel[self.s])
out = self.channel[self.s]
# close the connection with client
self.channel[out].close() # equivalent to do self.s.close()
# close the connection with remote server
self.channel[self.s].close()
# delete both objects from channel dict
del self.channel[out]
del self.channel[self.s]
def on_recv(self):
data = self.data
# Manipulate result
output = re.sub(r'uzgEmail1', r'TEST', data)
# Send result to client (DOESN'T WORK)
self.channel[self.s].send(output)
# Send result to client (WORKS when I disable send above)
self.channel[self.s].send(data)
if __name__ == '__main__':
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
server = AstLdapProxyServer(ASTLDAP_HOST, ASTLDAP_PROXY_PORT, tcpsock)
server.start()
try:
server.main_loop()
except KeyboardInterrupt:
sys.exit(1)