I am currently running into an issue where the following code only reads the first 1028 bytes from a socket, and then hangs waiting for more even though the rest has been sent. I thought it could be the code causing the problem, but it only happens when I am receiving data from the client to the server (which is multi-threaded). When I run the code in reverse (server sending data to client) it runs without an issue.
This is what is currently failing:
The clients code:
with open(commands[1], "rb") as file:
data = file.read()
# Sends the length of the file to the server
serverSocket.sendall(str(len(data)).encode())
# Sends the data to the server
data = file.read(1024)
while data:
data = file.read(1024)
serverSocket.sendall(data)
Along with the server code:
# Gets the total length of the file
dataLen = int(clientsocket.recv(1024).decode())
totalData = ""
while len(totalData) < dataLen:
# Reads in and appends the data to the variable
data = clientsocket.recv(1024).decode()
totalData += data
What else have I tried?
The original code for the client was:
with open(commands[1], "rb") as file:
data = file.read()
# Sends the length of the file to the server
serverSocket.sendall(str(len(data)).encode())
# Sends the data to the server
serverSocket.sendall(data)
Which I changed because I thought there may be an issue with the recv not getting all of the packets from the client, but the client believes that everything was sent.
Minimum Reproducible Code:
SERVER.PY
from socket import socket, AF_INET, SOCK_STREAM, error
from threading import Thread, Lock
from _thread import interrupt_main
import logging
from sys import stdout
from os import makedirs
from pathlib import Path
class Server:
def __init__(self, host, port):
logging.basicConfig(stream=stdout, level=logging.INFO, format='%(asctime)s - %(message)s')
self.host = host
self.port = port
self.quitVal = False
self.threads = []
self.lock = Lock()
self.sock = None
self.open()
def open(self):
sock = socket(AF_INET, SOCK_STREAM)
sock.bind((self.host, self.port))
sock.listen(5)
self.sock = sock
def listen(self):
try:
while self.quitVal != True:
(clientsocket, address) = self.sock.accept()
# This creates a threaded connection as this is the choke for the connection
thread = Thread(target=self.connection, args=(clientsocket, address), daemon=True)
self.threads.append(thread)
thread.start()
except OSError:
quit()
def connection(self, clientsocket, address):
while self.quitVal != True:
# We are going to allow multiple file transfers at one time on a connection
requestThreads = []
# The client innitially sends a command "s<command> [<fileLocation>]"
data = clientsocket.recv(4096).decode("utf-8")
data = data.split()
data[0] = data[0].lower()
if data[0] == "get":
thread = Thread(target=self.get, args=(clientsocket, data[1]), daemon=True)
requestThreads.append(thread)
thread.start()
elif data[0] == "put":
thread = Thread(target=self.put, args=(clientsocket, data[1]), daemon=True)
requestThreads.append(thread)
thread.start()
clientsocket.close()
def get(self, clientsocket, fileLocation):
# Tries to get the file, and sends it all to the client
with self.lock:
try:
with open(fileLocation, "rb") as file:
data = file.read()
# Sends the length of the file to the client
clientsocket.sendall(str(len(data)).encode())
# Byte to separate the input from length and file
response = self.sock.recv(1).decode()
# Sends the data to the client
clientsocket.sendall(data)
except IOError as e:
print("\nFile doesn't exist")
def put(self, clientsocket, fileLocation):
# Gets the total length of the file
with self.lock:
dataLen = int(clientsocket.recv(1024).decode())
totalData = ""
# Gets the total length of the file
dataLen = int(clientsocket.recv(1024).decode())
totalData = ""
# Byte to separate the input from length and file
clientsocket.sendall("0".encode())
while len(totalData) < dataLen:
# Reads in and appends the data to the variable
data = clientsocket.recv(2048).decode()
totalData += data
logging.info(totalData)
server = Server("127.0.0.1", 10002)
server.listen()
CLIENT.PY
from socket import socket, AF_INET, SOCK_STREAM, error
from threading import Thread, Lock
from _thread import interrupt_main
import logging
from sys import stdout
from os import makedirs
from pathlib import Path
class Client:
def __init__(self, host, port):
self.host = host
self.port = port
self.quitVal = False
self.sock = self.open()
self.threads = []
self.lock = Lock()
def open(self):
try:
sock = socket(AF_INET, SOCK_STREAM)
sock.connect((self.host, self.port))
except error as err:
return None
return sock
def get(self, commands):
# Sends the request for the file to the server using the main Sock
with self.lock:
command = "GET " + commands[0]
self.sock.send(command.encode())
dataLen = int(self.sock.recv(1024).decode())
totalData = ""
self.sock.sendall("0".encode())
while len(totalData) < dataLen:
data = self.sock.recv(2048).decode()
totalData += data
def put(self, commands):
with self.lock:
# Sends the put call command to the server
command = "PUT " + commands[1]
self.sock.sendall(command.encode())
try:
with open(commands[1], "rb") as file:
data = file.read()
# Sends the length of the file to the server
self.sock.sendall(str(len(data)).encode())
# Byte to separate the input from length and file
response = self.sock.recv(1).decode()
# Sends the data to the server
self.sock.sendall(data)
except IOError as e:
logging.info("\nFile doesn't exist")
client = Client("127.0.0.1", 10002)
print("foo")
client.get(["foo.txt", "bar.txt"])
client.put(["foo.txt", "bar1.txt"])
Related
I am having a Pickle issue with SSL client to server communication using multiprocessing.
I have an SSL client that connects to the server:
SSLClient.py
import socket
import struct
import ssl
import copyreg
from os import path
import socket
import os
from pathlib import Path
from loguru import logger as log
from utils.misc import read_py_config
from datetime import datetime
from cryptography.fernet import Fernet
fernetkey = '1234567'
fernet = Fernet(fernetkey)
class SSLclient:
license = None
licenseencrypted = None
uuid = None
def __init__(self):
try:
path = Path(__file__).parent / "/lcl" #get unique license key
with path.open() as file:
self.licenseencrypted = file.read().rstrip()
self.license = fernet.decrypt(str.encode(self.licenseencrypted)).decode('ascii')
self.host, self.port = "127.0.0.1", 65416
except Exception as e:
log.error("Could not decode license key")
def connect(self):
self.client_crt = os.path.join(os.path.dirname(__file__), 'key/c-.crt')
self.client_key = os.path.join(os.path.dirname(__file__), 'key/ck-.key')
self.server_crt = os.path.join(os.path.dirname(__file__), 'key/s-.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_crt, keyfile=self.client_key)
self._sock = None
self._ssock = None
## ---- 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))
log.info("Socket successfully created")
except socket.error as err:
log.error("socket creation failed with error %s" %(err))
return False
log.info('Waiting for connection')
return True
def closesockconnection(self):
self._ssock.close()
def checkvalidsite(self):
#check if site is active
jsonobj = {
"uuid": self.license,
"ipaddress" : self.external_ip,
"req": "checkvalidsite"
}
send_msg(self._ssock, json.dumps(jsonobj).encode('utf-8'))
active = False
while True:
Response = recv_msg(self._ssock)
if not Response:
return False
if Response is not None:
Response = Response.decode('utf-8')
Response = json.loads(Response)
req = Response['req']
if req == "checkvalidsite":
active = Response['active']
self.info1 = Response['info1']
self.info2 = Response['info2']
return active
# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg): # ---- Use this to send
try:
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
except Exception as e:
log.error("Sending message " + str(e))
def recv_msg(sock: socket): # ---- Use this to receive
try:
# 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)
except Exception as e:
log.error("Receiving message " + str(e))
return False
def recvall(sock: socket, n: int):
try:
# 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
except Exception as e:
log.error("Receiving all message " + str(e))
raise Exception(e)
I then have a server that is Multithreaded and accepts the connection and communicates with the client.
Server.py
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
from threading import Thread
import json
import mysql.connector as mysql
import time
from loguru import logger as log
import threading
from cryptography.fernet import Fernet
fernetkey = '12213423423'
fernet = Fernet(fernetkey)
threadLocal = threading.local()
# ---- To Avoid Message Boundary Problem on top of TCP protocol ----
def send_msg(sock: socket, msg): # ---- Use this to send
try:
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
except Exception as e:
log.error("Error send_msg " + str(e))
def recv_msg(sock: socket): # ---- Use this to receive
try:
# 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)
except Exception as e:
log.error("Receiving message " + str(e))
return False
def recvall(sock: socket, n: int):
try:
# 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
except Exception as e:
log.error("Receiving all message " + str(e))
raise Exception(e)
# ---- Server Communication Setup
class Newclient:
def __init__(self):
self.addr = None
self.conn = None
self.uuid = None
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.threads = []
self.sock = None
def checkvalidsite(self, uuid, ipaddress, cursor, db_connection):
sql = "select * from myexample where uuid ='" + uuid + "'"
cursor.execute(sql)
results = cursor.fetchall()
active = False
for row in results:
active = row["active"]
siteid = row["info1"]
clientid = row["info2"]
return active, siteid, clientid
def Serverthreaded_client(self, newclient):
conn = newclient.conn
try:
while True:
# data = conn.recv(2048) # receive message from client
data = recv_msg(conn)
uuid = None
ipaddress = None
req = None
if not data :
return False
if data is not None:
data = json.loads(data.decode('utf-8'))
uuid = data['uuid']
req = data['req']
if uuid is not None and req is not None:
newclient.uuid = uuid
cursor, db_connection = setupDBConnection()
if req == "checkvalidsite":
ipaddress = data['ipaddress']
active, info1, info2 = self.checkvalidsite(uuid, ipaddress, cursor, db_connection)
data = {
"req": "checkvalidsite",
"uuid": uuid,
"active": active,
"info1" : info1,
"info2" : info2
}
if not data:
break
# conn.sendall(str.encode(reply))
send_msg(conn, json.dumps(data).encode('utf-8'))
log.info("Server response sent")
#conn.close()
closeDBConnection(cursor, db_connection)
else:
#send no message
a=1
except Exception as e:
log.warning(str(e))
log.warning(traceback.format_exc())
finally:
log.info("UUID Closing connection")
conn.shutdown(socket.SHUT_RDWR)
conn.close()
#conn.close()
def Serverconnect(self):
try: # create socket
self.server_cert = path.join(path.dirname(__file__), "keys/server.crt")
self.server_key = path.join(path.dirname(__file__), "keys/server.key")
self.client_cert = path.join(path.dirname(__file__), "keys/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_cert_chain(certfile=self.server_cert, keyfile=self.server_key)
###self._context.load_verify_locations(self.client_cert)
self._context.load_verify_locations(cafile=self.client_cert)
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) ###<-- socket.socket() ???
log.info("Socket successfully created")
except socket.error as err:
log.warning("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:
log.warning(str(e))
log.info('Waiting for a Connection..')
self.sock.listen(3)
def Serverwaitforconnection(self):
while True:
Client, addr = self.sock.accept()
conn = self._context.wrap_socket(Client, server_side=True)
log.info('Connected to: ' + addr[0] + ':' + str(addr[1]))
log.info("SSL established. Peer: {}".format(conn.getpeercert()))
newclient = Newclient()
newclient.addr = addr
newclient.conn = conn
thread = Thread(target=self.Serverthreaded_client, args =(newclient, ))
thread.start()
self.threads.append(newclient)
self.ThreadCount += 1
log.info('Thread Number: ' + str(self.ThreadCount))
def startserver():
server = Server()
server.Serverconnect()
server.Serverwaitforconnection()
serverthread = Thread(target=startserver)
serverthread.daemon = False
serverthread.start()
The server accepts the connection with SSL then waits for a message. It investigates the message command, executes the respective function and returns the data from the database as a response (checkvalidsite in this example).
All good so far (as far as I can tell).
I also have the main program that calls the SSLClient and connects.
Main program
remoteclient = SSLclient()
successfulconnection = remoteclient.connect()
siteactive = remoteclient.checkvalidsite()
So far all is well. However I also have the main program reading in frames from multiple cameras. Can be 20 cameras for example. In order to do this I created multiprocessing to deal with the camera load. Each camera or two cameras per, are assigned to a processor (depending on the number of cores in the machine).
(code below has been stripped out to simplify reading)
x = range(3, 6)
for n in x:
processes = multiprocessing.Process(target=activateMainProgram, args=(queue1, queue2, queue3, queue4, remoteclient, ))
processes.start()
When I try pass the remoteclient (SSLClient) as an argument I get the error:
cannot pickle 'SSLContext' object
I then (after reading online) added the code to the SSLClient:
def save_sslcontext(obj):
return obj.__class__, (obj.protocol,)
copyreg.pickle(ssl.SSLContext, save_sslcontext)
but then I get the error:
cannot pickle 'SSLContext' object
There are 2 options I experimented with:
Trying to get the pickle working (which would be ideal) as the processes themselves each need to communicate with the server. So the processes need to call functions from the SSLClient file. But I cannot get over the pickle issue and can't find a solution online
I then placed the remoteclient = SSLClient code outside the main function. Hoping it would run first and then be accessible to the processes. This worked, however what I learnt was that when a process is called (as it does not share memory) it reprocesses the entire file. Meaning if I have 10 processes each with 2 cameras then I would have 10 connections to the server (1 per process). This means on the server side I would also have 10 threads running each connection. Though it works, it seems significantly inefficient.
Being a noob and self taught in Python I am not sure how to resolve the issue and after 3 days, I figured I would reach out for assistance. If I could get assistance with the pickle issue of the SSLClient then I will have one connection that is shared with all processes and 1 thread in the server to deal with them.
P.s. I have cobbled all of the code together myself and being new to Python if you see that I am totally going down the wrong, incorrect, non-professional track, feel free to yell.
Much appreciated.
Update:
If I change the SSLClient code to:
def save_sslcontext(obj):
return obj.__class__, (obj.protocol,)
copyreg.pickle(ssl.SSLContext, save_sslcontext)
Then I get the error:
[WinError 10038] An operation was attempted on something that is not a socket
Not sure what is better..
I'm creating a udp file transfer using python with a client (requests file from server), a server (receives request from client and passes it to the relevant worker) and worker1/worker2 (recieve request from server, if file exists, sends to server to pass back to client) and its all ran in docker containers with an ubuntu image*
Currently, when I type the name of the file I want in the client container, nothing works. I think the file name isn't actually being sent to the server but I can't figure out why at all. I was wondering if anyone can spot my mistake?
Server:
from fileinput import filename
import socket
import time
localIP = "127.0.0.1"
localPort = 50001
bufSize = 1024
msg = "Server is connecting..."
print(msg)
workerAddressPorts = [('127.0.0.1', 50002), ('127.0.0.1', 50003)]
# Create datagram sockets and bind to address and ip
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPServerSocket.bind((localIP, localPort))
print("Server is waiting for packet...")
while True:
bytesAddressPair = UDPServerSocket.recvfrom(bufSize)
clientBuf = bytesAddressPair[0]
clientAddr = bytesAddressPair[1]
msgFrom = 'Message from Client:{}'.format(clientBuf.decode('utf-8'))
print(msgFrom)
for workerAddressPort in workerAddressPorts:
UDPServerSocket.sendto(clientBuf, workerAddressPort) # send file name to worker
print(f'Clients request has been sent to Worker {workerAddressPort[0]}')
workerBuf = UDPServerSocket.recvfrom(bufSize)[0] # saving data from worker
print(f'Request recieved.')
UDPServerSocket.sendto(workerBuf, clientAddr) # sending data to client
print('Packet from Worker has been sent to Client')
while not workerBuf: # split file to prevent buffer overflow
workerBuf = UDPServerSocket.recvfrom(bufSize)[0]
print(f'Packet received.')
UDPServerSocket.sendto(workerBuf, clientAddr)
print('Packet from worker has been sent to Client')
print('File has been sent to Client.')
Client:
import sys
msgFrom = input('Name of file: ')
print(msgFrom)
bytesToSend = str.encode(msgFrom, 'utf-8')
serverAddressPort = ("127.0.0.1", 50001)
bufSize = 1024
# create UDP Client Socket and send to server
UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPClientSocket.sendto(bytesToSend, serverAddressPort)
while (True):
try:
serverBuf = UDPClientSocket.recvfrom(bufSize)[0]
if len(serverBuf) > 0:
print('Packet incoming...')
msg = serverBuf.decode('utf-8')
if msg == 'NO_FILE':
print('No such file exists.')
break
elif msg == 'END_OF_FILE':
print('Empty file.')
break
else:
f = open(msgFrom, 'wb')
f.write(serverBuf)
f.close()
except Exception as e:
print(e)
Worker:
import socket
import time
from os.path import exists
bufSize = 1024
msg = "Worker is connecting..."
print(msg)
serverAddressPort = ("127.0.0.1", 50001)
# Create a datagram socket and bind to address and ip
UDPWorkerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPWorkerSocket.bind(('127.0.0.1', 50002))
print("Worker is connected and waiting...")
while True:
time.sleep(1)
bytesAddressPair = UDPWorkerSocket.recvfrom(bufSize)
msg = bytesAddressPair[0]
addr = bytesAddressPair[1]
print('Packet Incoming...')
file_name = msg.decode('utf-8')
script_dir = os.path.dirname("C:/Users/Vic/Documents/3rd Year TCD/CSU33031 Computer Networks/Assignments/Assignment1.3/Files to send")
abs_file_path = os.path.join(script_dir, file_name)
if exists(file_name):
f = open(file_name, 'rb')
data = f.read(bufSize)
while data:
if UDPWorkerSocket.sendto(data, serverAddressPort):
data = f.read(bufSize)
time.sleep(1)
print('Sent to Server.')
else:
UDPWorkerSocket.sendto(str.encode('NO_FILE'), serverAddressPort)
print(f'{file_name} was not found. Moving to next available worker..')
Hoping that the for statement in the server, iterates the two worker files(only included one) so if it can't find the file in one worker it moves to the other
*the client is connected to a different network as the two workers. The server is connected to both networks
Thanks in advance!!
So now I have a server and client script. I'm trying to upload a file from the client to the server. However, the data from the file in the client will be cut out by the HEADER size. How do I send multiple packets under the same send command to the server?
server.py:
import socket
import threading
HEADER=2048
PORT=5050
SERVER=socket.gethostbyname(socket.gethostname())
ADDR=(SERVER,PORT)
FORMAT='utf-8'
DISCONNECT_MESSAGE='!DISCONNECT'
SEPARATOR='<SEPERATE>'
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(ADDR)
def handle_client(conn,addr):
print(f'[NEW CONNECTION] {addr} connected.')
connected=True
while connected:
data=conn.recv(HEADER).decode(FORMAT)
if data==DISCONNECT_MESSAGE:
connected=False
else:
data=data.split(SEPARATOR)
file=open(data[0],'w')
file.write(data[1])
print('file received')
conn.send('file received'.encode(FORMAT))
conn.close()
print(f'[DISCONNECT] {addr} disconnected')
def start():
server.listen()
print(f'[LISTENING] Server is listening on {SERVER}')
while True:
conn,addr=server.accept()
thread=threading.Thread(target=handle_client,args=(conn,addr))
thread.start()
print(f'[ACTIVE CONNECTIONS] {threading.activeCount()-1}')
print("[STARTING] server is starting...")
start()
client.py:
import socket
HEADER=2048
PORT=5050
FORMAT='utf-8'
DISCONNECT_MESSAGE='!DISCONNECT'
SEPARATOR='<SEPERATE>'
SERVER=socket.gethostbyname(socket.gethostname())
ADDR=(SERVER,PORT)
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(ADDR)
def send(msg):
message=msg.encode(FORMAT)
client.send(message)
print(client.recv(HEADER).decode(FORMAT))
file=open('question_pool.csv','r')
data=file.read()
send(f'question_pool.csv{SEPARATOR}{data}')
file.close()
send(DISCONNECT_MESSAGE)
In short, you want to send multiple chunks of any file that is larger than your HEADER size. Split the file into chunks smaller than the HEADER size, and send each chunk individually. Then when all the chunks are set, send a message that says the whole file has been sent so that the server can save it.
Here is my code for the solution described above:
server.py:
import socket
import threading
HEADER = 2048
PORT = 5050
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = '!DISCONNECT'
SEPARATOR = '<SEPERATE>'
FILE_FINISHED_SENDING = '<!FILE_SENT!>'
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(ADDR)
def handle_client(conn, addr):
print(f'[NEW CONNECTION] {addr} connected.')
connected = True
current_file = None
while connected:
data = conn.recv(HEADER).decode(FORMAT)
if data == DISCONNECT_MESSAGE:
connected = False
elif data == FILE_FINISHED_SENDING:
current_file.close()
current_file = None
conn.send(b'file received.')
else:
data = data.split(SEPARATOR)
if len(data) == 2 and data[1] == '':
# The name of the file was sent, more will follow.
current_file = open(data[0], 'w')
conn.send(b'filename recieved')
else:
# File data was send, so write it to the current file
current_file.write(data[1])
print('chunk of file recv''d')
conn.send(b'chunk received')
conn.close()
print(f'[DISCONNECT] {addr} disconnected')
def start():
server.listen()
print(f'[LISTENING] Server is listening on {SERVER}')
while True:
conn, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(conn,addr))
thread.start()
print(f'[ACTIVE CONNECTIONS] {threading.activeCount()-1}')
print("[STARTING] server is starting...")
start()
client.py:
import socket
from pathlib import Path
HEADER = 2048
PORT = 5050
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = '!DISCONNECT'
SEPARATOR = '<SEPERATE>'
FILE_FINISHED_SENDING = '<!FILE_SENT!>'
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)
def chunker(string: str, size: int):
return (string[pos:pos + size] for pos in range(0, len(string), size))
def send(msg):
message = msg.encode(FORMAT)
client.send(message)
print(client.recv(HEADER).decode(FORMAT))
def send_file(filepath: str):
with open(filepath, 'r', encoding=FORMAT) as f:
data = f.read()
first_bits = f'{Path(filepath).name}{SEPARATOR}' # Easy way of getting just a file's name from its path
send(first_bits) # Send the filename to the server
for chunk in chunker(data, HEADER-48): # Leave a safe buffer
# Send each chunk of the file
send(f"{SEPARATOR}{chunk}")
# Tell the server that's all for this file.
# Now it can close the file object.
send(FILE_FINISHED_SENDING)
send_file("/path/to/file.html")
send(DISCONNECT_MESSAGE)
Tips:
make sure that your special messages like SEPARATOR, FILE_FINISHED_SENDING and DISCONNECT_MESSAGE are NOT going to appear in the files you are sending. Otherwise things might get wonky.
You may want to read files as raw bytes when you send them through the socket, instead of reading as strings, encoding, decoding, etc. This way you could send binary files such as .mp3, for example.
This is a simple port forwarding proxy which listens on localhost and then forwards all the connection to a real proxy and sends back the received data to the user.
The server which accepts connections and listens:
class Server:
def __init__(self):
self.server = eventlet.listen(('127.0.0.1', 8080))
self.chunk_size = 8192
def forward_connection(self, fd):
print('in fwd_conn')
data = b''
while True:
print('reading data')
x = fd.readline()
if not x.strip():
break
data += x
print('Got request:', data)
client = Client('45.55.31.207', 8081, data) # Connecting to proxy
buff = client.read_from_proxy()
fd.write(buff)
fd.flush()
def serve_client(self):
pool = eventlet.GreenPool()
while True:
try:
new_sock, addr = self.server.accept()
print('accepted:', addr)
pool.spawn(self.forward_connection, new_sock.makefile('rbw'))
except (SystemExit, KeyboardInterrupt):
break
server = Server()
server.serve_client()
This part of the code connects to the 'real' proxy, receives the data and sends it back. But as commented in the read_from_proxy function, it isn't receiving any data:
class Client:
''' All connections from Server are forwarded to Client which then
forwards it to the proxy '''
def __init__(self, ip, port, request):
self.sock = socket.socket()
self.sock.connect((ip, port))
print('in client')
print('sent request:', request)
self.request = request
def read_from_proxy(self):
self.sock.sendall(self.request)
data = b''
while True:
print('reading data from proxy') # this executes
x = self.sock.recv(8192) # but this doesn't, it gets blocked here
print('got x:', x)
if not x.strip():
break
data += x
print('read all data')
return data
Where am I going wrong?
so right now in order to receive your message you need to receive one
my teachers instructions are (in the main)"Modify the loop so that it only listens for keyboard input and then sends it to the server."
I did the rest but don't understand this, ... help?
import socket
import select
import sys
import threading
'''
Purpose: Driver
parameters: none
returns: none
'''
def main():
host = 'localhost'
port = 5000
size = 1024
#open a socket to the client.
try:
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((host,port))
#exit on error
except socket.error, (value,message):
if clientSock :
clientSock.close()
print "Could not make connection: " + message
sys.exit(1)
thread1 = ClientThread()
thread1.start()
while True:
#wait for keyboard input
line = raw_input()
#send the input to the server unless its only a newline
if line != "\n":
clientSock.send(line)
#wait to get something from the server and print it
data = clientSock.recv(size)
print data
class ClientThread(threading.Thread):
'''
Purpose: the constructor
parameters: the already created and connected client socket
returns: none
'''
def __init__(self, clientSocket):
super(ClientThread, self).__init__()
self.clientSocket = clientSocket
self.stopped = False
def run(self):
while not self.stopped:
self.data = self.clientSocket.recv(1024)
print self.data
main()
I assume your purpose is to create a program that starts two threads, one (client thread) receives keyboard input and sends to the other (server thread), the server thread prints out everything it received.
Based on my assumption, you first need to start a ServerThread listen to a port (it's not like what your 'ClientThread' did). Here's an example:
import socket
import threading
def main():
host = 'localhost'
port = 5000
size = 1024
thread1 = ServerThread(host, port, size)
thread1.start()
#open a socket for client
try:
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((host,port))
except socket.error, (value,message):
if clientSock:
clientSock.close()
print "Could not connect to server: " + message
sys.exit(1)
while True:
#wait for keyboard input
line = raw_input()
#send the input to the server unless its only a newline
if line != "\n":
clientSock.send(line)
# Is server supposed to send back any response?
#data = clientSock.recv(size)
#print data
if line == "Quit":
clientSock.close()
break
class ServerThread(threading.Thread):
def __init__(self, host, port, size):
super(ServerThread, self).__init__()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((host, port))
self.sock.listen(1)
self.data_size = size
self.stopped = False
def run(self):
conn, addr = self.sock.accept()
print 'Connected by', addr
while not self.stopped:
data = conn.recv(self.data_size)
if data == 'Quit':
print 'Client close the connection'
self.stopped = True
else:
print 'Server received data:', data
# Is server supposed to send back any response?
#conn.sendall('Server received data: ' + data)
conn.close()
if __name__ == '__main__':
main()
And these are the output:
Connected by ('127.0.0.1', 41153)
abc
Server received data: abc
def
Server received data: def
Quit
Client close the connection
You may check here for more details about Python socket: https://docs.python.org/2/library/socket.html?#example