Unable to find Ethernet or socket connection exist in python socket - python

i have a small client application which needs to maintain a persistent socket connection to the server.
The connection establishment seems to work fine. also when the server closes the socket i am able to detect.
But when the client Ethernet cable is unplugged .it never throws a exception when i try send or receive data in sock.
when i try to send i get send data success and when i try to receive i get receive timeout
what i am missing in my class.Please guide
Note : it almost took 14 mins for the socket to find disconnect
KEEP ALIVE DATA:
echo 30 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
echo 30 > /proc/sys/net/ipv4/tcp_keepalive_time
code implementation:
import logFormat as log
import socket
import traceback
import sys
import select
import time
import messageId as messasgeId # Name convention to be decided Many DB access done through this class
def synchronized(L):
def lock_around(f):
def locked(*a, **k):
with L:
return f(*a, **k)
locked.__name__ = f.__name__
locked.__doc__ = f.__doc__
return locked
return lock_around
class socketHandler(object):
__single = None # the one, true Singleton
def __new__(classtype, *args, **kwargs):
if classtype != type(classtype.__single):
classtype.__single = object.__new__(classtype, *args, **kwargs)
return classtype.__single
def __init__(self, name=None):
self.name = name
self.throttleCount = 100
self.loggerCount = 0
self.timeoutDefault=0.2
def socketSend(self, data):
try:
self.sock.send(data)
log.debugLog("Socket data send complete", True)
return True
except:
log.debugLog("Socket data send with error/timeout", True)
raise
def recieveProtoBufHeader(self, headerLength, timeout=10):
try:
self.sock.settimeout(timeout)
expHeaderBytes = ord(headerLength)
log.debugLog("Expected socket data length: %s with timeout: %s" % (expHeaderBytes, timeout), True)
HeaderData = self.sock.recv(expHeaderBytes)
log.debugLog("Data received in socket: %s" % HeaderData, True)
self.sock.settimeout(self.timeoutDefault)
return HeaderData
except:
log.debugLog("recieveProtoBufHeader with error/timeout", True)
raise
def recieveProtoBufData(self, dataSize, timeout=0.1):
try:
log.debugLog("Expected socket data length: %s with timeout: %s" % (dataSize, timeout), True)
self.sock.settimeout(timeout)
dataBuffer = self.sock.recv(dataSize)
log.debugLog("Data received in socket: %s" % dataBuffer, True)
self.sock.settimeout(self.timeoutDefault)
return dataBuffer
except:
log.debugLog("recieveProtoBufData with error/timeout", True)
raise
def recieveData(self, dataSize, timeout=0.1):
try:
self.sock.settimeout(timeout)
dataBuffer = self.sock.recv(1)
if len(dataBuffer) == dataSize:
log.debugLog("Data received in socket: %s" % dataBuffer.encode('hex'), True)
log.debugLog("Data received length: %s" % len(dataBuffer), True)
else:
self.sock.close()
log.debugLog("Server side socket closed raising socket error", True)
raise socket.error, "Socket error raised"
self.sock.settimeout(self.timeoutDefault)
return dataBuffer
except socket.timeout:
raise # Can add log foo socket timeout
except:
log.debugLog("Unknown exception occurred so closing socket ", True)
self.sock.close()
raise
def recieveDataCheck(self):
try:
self.sock.settimeout(0.2)
dataBuffer = self.sock.recv(1)
if len(dataBuffer) == 1:
log.debugLog("Data received in socket: %s" % dataBuffer.encode('hex'), True)
log.debugLog("Data received length: %s" % len(dataBuffer), True)
else:
self.sock.close()
log.debugLog("Server side socket closed raising socket error", True)
raise socket.error, "Socket error raised"
return dataBuffer
except socket.timeout:
raise # Can add log foo socket timeout
except:
log.debugLog("Unknown exception occurred so closing socket ", True)
self.sock.close()
raise
def closeSocket(self):
try:
self.sock.close()
self.sock = None
return True
except:
log.debugLog("Close socket with error", True)
raise
def recieveCheck(self):
try:
ready = select.select([self.sock], [], [], 0.2)
print ready
if len(ready[0]) == 0:
return True
else:
return False
except:
raise
def connectSocket(self, retryCount=5):
try:
self.loggerCount+=1
if self.loggerCount % self.throttleCount == 0:
throttleLog=True
else:
throttleLog=False
#host = "192.168.10.134"
host = messasgeId.getSwitchIP()
# host = "localhost"
#port = int(8001)
port = int(messasgeId.getSwitchPort())
log.debugLog("connection with switch server ip: %s port: %s on progress" % (host, port), True)
while retryCount:
self.sock = None
self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
#self.sock.bind(host,port)
self.sock.settimeout(0.1)
try:
self.sock.connect((host, port))
#assert(self.recieveCheck())
log.debugLog("Socket connection established successfully", True)
self.loggerCount = 0
return True
except:
log.debugLog("Socket Connection Retry Count Remaining Progress(%s)" % retryCount, True)
time.sleep(5)
retryCount -= 1
if retryCount == 0:
return False
return False
except:
log.debugLog("Unexpected error in socket connection", True)
raise

Related

Python UDP throughput is much slower than TCP throughput

I made two applications ('Client' and 'Server') written in Python.
On each of them beyond main thread I created two additonal threads, which are handling operations of sending / receiving data from each TCP / UDP parts.
So for client I have written code for:
clientTCP part:
class ClientTCP:
def __init__(self, host_address: str, port: int):
self.client_socket = None
self.host_address = host_address
self.port = port
def connect_to_server(self, is_nagle_disabled: bool):
try:
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if is_nagle_disabled:
self.client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
self.client_socket.connect((self.host_address, self.port))
except socket.error:
print('Error: probably wrong port passed for connection')
sys.exit(1)
def send_message_to_server(self, user_input: str):
try:
#print(f'MESSAGE TO SEND AS CLIENT TCP: {user_input}')
self.client_socket.sendall(bytes(user_input, 'utf-8'))
except socket.error as e:
print('OVER HERE SEND MESSAGE TCP ERROR')
print(f'Error: {e}')
self.client_socket.close()
sys.exit(1)
def receive_message_from_server(self, buffer_size: int):
data_from_server = []
while True:
byte_portion_of_data = self.client_socket.recv(buffer_size)
if byte_portion_of_data.decode("utf-8") in ['BUSY', 'READY']:
return data_from_server
elif byte_portion_of_data:
#print(f'TCP -> byte portion of data: {byte_portion_of_data.decode("utf-8")}')
data_from_server.append(byte_portion_of_data)
else:
print('Entirety of message from server received')
break
return data_from_server
def get_client_socket(self):
return self.client_socket
def __del__(self):
self.client_socket.close()
def tcp_send_data_to_server(client: ClientTCP, data_to_send: list[int], size_of_buffer: int, is_nagle_disabled: bool, stop):
try:
#print('OVER HERE TCP!!!')
client.connect_to_server(is_nagle_disabled)
client_connection_list = client.receive_message_from_server(10)
client_connection_message = ''.join([x.decode("utf-8") for x in client_connection_list])
if client_connection_message == 'BUSY':
return
elif client_connection_message == 'READY':
client.send_message_to_server(f"SIZE:{str(size_of_buffer)}")
while True:
#print("TCP!!!")
if stop():
break
message_to_send = ''.join([str(x) for x in data_to_send])
client.send_message_to_server(message_to_send)
time.sleep(1)
except ConnectionResetError:
print("Socket was closed due to some unknown reasons. Sorry. :(")
senderUDP
class SenderUDP:
def __init__(self, host_address: str, port: int):
self.client_socket = None
self.host_address = host_address
self.port = port
def connect_to_server(self):
try:
self.client_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
except socket.error as e:
print(str(e))
sys.exit(1)
def send_message_to_server(self, input_to_send: str):
try:
#print(input_to_send)
#print('OVER HERE 1 UDP send')
self.client_socket.sendto(input_to_send.encode(), (self.host_address, self.port))
#print('OVER HERE 2 UDP send')
except Exception as e:
print('Error: ' + str(e))
self.client_socket.close()
sys.exit(1)
def get_client_socket(self):
return self.client_socket
def __del__(self):
self.client_socket.close()
def sending(sender: SenderUDP, data_to_send: list[int], size_of_buffer: int, stop):
try:
sender.connect_to_server()
sender.send_message_to_server(f"SIZE:{size_of_buffer}")
while True:
#print("UDP!!!")
if stop():
sender.send_message_to_server('END')
break
message_to_send = ''.join([str(x) for x in data_to_send])
sender.send_message_to_server(message_to_send)
sleep(1)
except ConnectionResetError:
print("Socket was closed due to some unknown reasons. Sorry. :(")
As for the 'Server' part:
serverTCP
import socket
import sys
import re
import time
from datetime import datetime
class ServerTCP:
def __init__(self, address, port, buffer: int):
self.server_socket = None
self.host_address = address
self.port = port
self.number_of_clients = 0
self.buffer = buffer
self.client_socket = None
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
def create_socket(self):
try:
socket.inet_aton(self.host_address)
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.host_address, self.port))
except socket.error:
print('Error: ' + str(socket.error))
sys.exit(1)
def start_listening(self):
try:
self.server_socket.listen(1)
except socket.error as msg:
print('Error: ' + str(socket.error))
self.server_socket.close()
sys.exit(1)
def set_client_socket(self, client_socket):
self.client_socket = client_socket
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
self.client_socket.send('READY'.encode())
def handle_another_client(self, another_client_socket):
another_client_socket.send('BUSY'.encode())
another_client_socket.close()
def remove_client_socket(self):
self.client_socket.shutdown(socket.SHUT_WR)
self.client_socket.close()
self.buffer = 100
self.client_socket = None
def get_server_socket(self):
return self.server_socket
def get_client_socket(self):
return self.client_socket
def get_transmission_data(self):
return self.count_bytes_from_client / 1000, self.count_time_in_seconds
def __del__(self):
self.server_socket.shutdown(socket.SHUT_RDWR)
self.server_socket.close()
print("Server socket closed")
def __str__(self):
kbytes, time = self.get_transmission_data()
return f"TCP: {kbytes} per {time} seconds"
def tcp_get_data_from_client(server: ServerTCP):
# data_from_client = []
try:
start = datetime.now()
while True:
byte_portion_of_data = server.client_socket.recv(server.buffer)
if not byte_portion_of_data:
break
# data_from_client.append(byte_portion_of_data)
string_data_from_client = byte_portion_of_data.decode('utf-8')
if string_data_from_client.startswith('SIZE:'):
temp = re.findall(r'\d+', string_data_from_client[5:])
res = list(map(int, temp))
if len(res) != 0:
server.buffer = res[0]
start = datetime.now()
else:
server.count_bytes_from_client += len(string_data_from_client)
#print('End of the ServerTCP loop')
time.sleep(0)
end = datetime.now()
server.count_time_in_seconds += (end - start).total_seconds()
print(server)
server.remove_client_socket()
except ConnectionResetError:
print("Socket was closed due to some unknown reasons. Sorry. :(")
receiverUDP
import socket
import struct
import sys
import re
import time
from datetime import datetime
class ReceiverUDP:
def __init__(self, group, port: int, buffer: int):
self.group = group
self.port = port
self.socket = None
self.buffer = buffer
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
self.start = None
def starting(self):
try:
self.socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
self.socket.bind((self.group, self.port))
except socket.error as e:
print(f'Error: {str(e)}')
def get_transmission_data(self):
return self.count_bytes_from_client / 1000, self.count_time_in_seconds
def clean_transmission_data(self):
self.count_bytes_from_client = 0
self.count_time_in_seconds = 0
def close_of_receiver(self):
try:
self.socket.close()
except socket.error as e:
print(f'Error: {str(e)}')
def __str__(self):
kbytes, time = self.get_transmission_data()
return f"UDP: {kbytes} per {time}"
def receiving(receiver: ReceiverUDP, stop_thread):
is_first_client = True
try:
#print('Start of ReceiverUDP')
while True:
#print('Before recvfrom, ReceiverUDP')
#print(f'Start buffer: {receiver.buffer}')
data = receiver.socket.recvfrom(receiver.buffer)
message = data[0].decode("utf-8")
print(f"Server UDP, message: {message}")
if message.startswith("SIZE:"):
temp = re.findall(r'\d+', message[5:])
res = list(map(int, temp))
print(f'New buffer: {res[0]}')
if len(res) != 0:
if is_first_client:
receiver.start = datetime.now()
is_first_client = False
receiver.buffer = res[0]
print(f'New buffer assigned: {receiver.buffer}')
elif message.__contains__("END"):
receiver.count_time_in_seconds += (datetime.now() - receiver.start).total_seconds()
receiver.start = datetime.now()
print(receiver)
else:
receiver.count_bytes_from_client += len(message)
#print(f"Message from Server: ")
time.sleep(0)
except ConnectionResetError:
print(receiver)
print("Socket was closed due to some unknown reasons. Sorry. :(")
Static methods are of course 'thread' methods also.
Now back into the problem. I read on the internet that UDP transmission should be much faster than TCP. But that's not the case, in fact it's complete opposite for me.
When I put Server part on the container and run it + launched client with 'typed host_address' of docker gateway (it's something like 172.16.0.1') I got the same thing as earlier on running both on my machine.
On server application output I got such statistics for both TCP and UDP:
TCP: 2.3kB per 15.004 sec
UDP: 1.5kB per 15.009 sec
So clearly even now UDP is much slower than TCP. Why is that and what I did wrong?
I would be grateful for all advices.
Python UDP throughput is much slower than TCP throughput
This is to be expected. TCP is optimized for low overhead and will combine multiple send into as few packets on the wire as possible. With UDP instead each send will result in a single packet with all the overhead.
This overhead is especially noticable if the datagrams (i.e. the payload of send) are significantly smaller than the MTU of the link. And from a short look at your code it looks like that your are sending several small datagrams.
Apart from that it looks like you assume that a single send in the sender will match a single recv in the recipient. This is not true for TCP since data can be combined to reduce overhead: TCP is not a message protocol but an unstructured byte stream. The assumption is more or less true with UDP, but contrary to TCP there might be packet loss, packet reordering and duplication which you currently don't account for.

Chat server and chat client

This program has both the ChatServer class and ChatClient class in the same file, and should be called in the terminal by --name=server --port=8800 for the server and --name=client1 --port=8800 for the client. The problem comes from the client class not being able to complete a try:
When running the program with server name, it seems to work fine. When it runs with client name, I get the output Failed to connect to chat server # port 8800.
You can find where this except statement lies.
import select
import socket
import sys
import signal
import _pickle as cPickle
import struct
import argparse
SERVER_HOST = 'localhost'
CHAT_SERVER_NAME = 'server'
# Some utilities
def send(channel, *args):
buffer = cPickle.dumps(args)
value = socket.htonl(len(buffer))
size = struct.pack("L", value)
channel.send(size)
channel.send(buffer)
def receive(channel):
size = struct.calcsize("L")
size = channel.recv(size)
try:
size = socket.ntohl(struct.unpack("L", size)[0])
except struct.error as e:
return ''
buf = ""
while len(buf) < size:
buf = channel.recv(size - len(buf))
return cPickle.loads(buf)[0]
class ChatServer(object):
def __init__(self, port, backlog=5):
self.clients = 0
self.clientmap = {}
self.outputs = []
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Enable re-using socket address
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server.bind((SERVER_HOST, port))
print('Server listening to port: %s...' % port)
self.server.listen(backlog)
# Catch keyboard interrupts
signal.signal(signal.SIGINT, self.sighandler)
def sighandler(self, signum, frame):
# Close the server
print("Shutting down server...")
# Close existing client sockets
for output in self.outputs:
output.close()
self.server.close()
def get_client_name(self,client):
info = self.clientmap[client]
host, name = info[0][0], info[1]
return '#'.join((name, host))
def run(self):
inputs = [self.server, sys.stdin]
self.outputs = []
running = True
while running:
try:
readable, writeable, exceptional = select.select(inputs, self.outputs, [])
except select.error as e:
break
for sock in readable:
if sock == self.server:
# handle the server socket
client, address = self.server.accept()
print("Chat Server: got connection %d from %s" % (client.fileno(), address))
# Read the login name
cname = receive(client).split('NAME: ')[1]
# Compute client name ad send back
self.clients += 1
send(client, 'CLIENT: ' + str(address[0]))
inputs.append(client)
self.clientmap[client] = (address, cname)
# Send joining information to other clients
msg = "\n(Connected: New client (%d) from %s)" % (self.clients, self.get_client_name(client))
for output in self.outputs:
send(output, msg)
self.outputs.append(client)
elif sock == sys.stdin:
# Handle standard input
junk = sys.stdin.readline()
running = False
else:
# Handle all other sockets
try:
data = receive(sock)
if data:
# Send as new client's message..
msg = '\n[' + self.get_client_name(sock) + ']>>' + data
# Send data to all except ourself
for output in self.outputs:
if output != sock:
send(output, msg)
else:
print("Chat server: %d hung up" % sock.fileno())
self.clients -= 1
sock.close()
inputs.remove(sock)
self.outputs.remove(sock)
# Sending client leaving info to others
msg = "\n(Now hung up: Client from %s" % self.get_client_name(sock)
for output in self.outputs:
send(output, msg)
except socket.error as e:
# Remove
inputs.remove(sock)
self.outputs.remove(sock)
self.server.close()
class ChatClient(object):
def __init__(self, name, port, host=SERVER_HOST):
self.name = name
self.connected = False
self.host = host
self.port = port
# Initial Prompt
self.prompt = '[' + '#'.join((name, socket.gethostname().split('.')[0])) + ']> '
# Connect to server at port
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((host, self.port))
print("Now connected to chat server# port %d" % self.port)
self.connected = True
# Send by name...
send(self.sock, 'NAME: ' + self.name)
data = receive(self.sock)
# Contains client address, set it
addr = data.split('CLIENT: ')[1]
self.prompt = '[' + '#'.join((self.name, addr)) + ']>'
except socket.error as e:
print("Failed to connect to chat server # port %d" % self.port)
sys.exit(1)
def run(self):
while self.connected:
try:
sys.stdout.write(self.prompt)
sys.stdout.flush()
# Wait for input from stdin and socket
readable, writable, exceptional = select.select([0, self.sock], [], [])
for sock in readable:
if sock == 0:
data = sys.stdin.readline().strip()
if data:
send(self.sock, data)
elif sock == self.sock:
data = receive(self.sock)
if not data:
print('Client shutting down')
self.connected = False
break
else:
sys.stdout.write(data + '\n')
sys.stdout.flush()
except KeyboardInterrupt:
print("Client interrupted")
self.sock.close()
break
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Socket Server Example with Select')
parser.add_argument('--name', action="store", dest="name", required=True)
parser.add_argument('--port', action="store", dest="port", type=int, required=True)
given_args = parser.parse_args()
port = given_args.port
name = given_args.name
if name == CHAT_SERVER_NAME:
server = ChatServer(port)
server.run()
else:
client = ChatClient(name=name, port=port)
client.run()

I got connection refused for python TCP HolePunching

This is the code in serverside:
#!/usr/bin/env python
import sys
import logging
import socket
import struct
import fcntl
import os
from util import *
logger = logging.getLogger()
clients = {}
def main(host='**client public ip**', port=3443):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
s.listen(1)
s.settimeout(30)
while True:
try:
conn, addr = s.accept()
except socket.timeout:
continue
logger.info('connection address: %s', addr)
data = recv_msg(conn)
priv_addr = msg_to_addr(data)
send_msg(conn, addr_to_msg(addr))
data = recv_msg(conn)
data_addr = msg_to_addr(data)
if data_addr == addr:
logger.info('client reply matches')
clients[addr] = Client(conn, addr, priv_addr)
else:
logger.info('client reply did not match')
conn.close()
logger.info('server - received data: %s', data)
if len(clients) == 2:
(addr1, c1), (addr2, c2) = clients.items()
logger.info('server - send client info to: %s', c1.pub)
send_msg(c1.conn, c2.peer_msg())
logger.info('server - send client info to: %s', c2.pub)
send_msg(c2.conn, c1.peer_msg())
clients.pop(addr1)
clients.pop(addr2)
conn.close()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
main(*addr_from_args(sys.argv))
and this is clientside:
#!/usr/bin/env python
import sys
import logging
import socket
import struct
from threading import Event, Thread
from util import *
logger = logging.getLogger('client')
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
STOP = Event()
def accept(port):
logger.info("accept %s", port)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind(('**server's public ip**', port))
s.listen(1)
s.settimeout(5)
while not STOP.is_set():
try:
conn, addr = s.accept()
except socket.timeout:
continue
else:
logger.info("Accept %s connected!", port)
# STOP.set()
def connect(local_addr, addr):
logger.info("connect from %s to %s", local_addr, addr)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind(local_addr)
while not STOP.is_set():
try:
s.connect(addr)
except socket.error:
continue
# except Exception as exc:
# logger.exception("unexpected exception encountered")
# break
else:
logger.info("connected from %s to %s success!", local_addr, addr)
# STOP.set()
def main(host='**client's local ip**', port=3443):
sa = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sa.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sa.connect((host, port))
priv_addr = sa.getsockname()
send_msg(sa, addr_to_msg(priv_addr))
data = recv_msg(sa)
logger.info("client %s %s - received data: %s", priv_addr[0], priv_addr[1], data)
pub_addr = msg_to_addr(data)
send_msg(sa, addr_to_msg(pub_addr))
data = recv_msg(sa)
pubdata, privdata = data.split(b'|')
client_pub_addr = msg_to_addr(pubdata)
client_priv_addr = msg_to_addr(privdata)
logger.info(
"client public is %s and private is %s, peer public is %s private is %s",
pub_addr, priv_addr, client_pub_addr, client_priv_addr,
)
threads = {
'0_accept': Thread(target=accept, args=(priv_addr[1],)),
'1_accept': Thread(target=accept, args=(client_pub_addr[1],)),
'2_connect': Thread(target=connect, args=(priv_addr, client_pub_addr,)),
'3_connect': Thread(target=connect, args=(priv_addr, client_priv_addr,)),
}
for name in sorted(threads.keys()):
logger.info('start thread %s', name)
threads[name].start()
while threads:
keys = list(threads.keys())
for name in keys:
try:
threads[name].join(1)
except TimeoutError:
continue
if not threads[name].is_alive():
threads.pop(name)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, message='%(asctime)s %(message)s')
main(*addr_from_args(sys.argv))
and this is the util.py code:
import struct
from collections import namedtuple
def addr_from_args(args, host='**server's local ip**', port=9999):
if len(args) >= 3:
host, port = args[1], int(args[2])
elif len(args) == 2:
host, port = host, int(args[1])
else:
host, port = host, port
return host, port
def msg_to_addr(data):
ip, port = data.decode('utf-8').strip().split(':')
return (ip, int(port))
def addr_to_msg(addr):
return '{}:{}'.format(addr[0], str(addr[1])).encode('utf-8')
def send_msg(sock, msg):
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recvall(sock, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data
def recv_msg(sock):
# 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)
class Client(namedtuple('Client', 'conn, pub, priv')):
def peer_msg(self):
return addr_to_msg(self.pub) + b'|' + addr_to_msg(self.priv)
and this is the error:
Traceback (most recent call last):
File "tcpclient.py", line 96, in <module>
main(*addr_from_args(sys.argv))
File "tcpclient.py", line 55, in main
sa.connect((host, port))
ConnectionRefusedError: [Errno 111] Connection refused
It's working in same network but in different one not!!
For adding more details I would say that we have one client and on server that wanna communicate to each other, client and server are both behind the nat and the server has webserver and client want to go to the webserver but because of the nat problem it can't. so we are trying to make a hole punching peer to peer connection to make client able to see the webserver.
we can't take any kind of ip static or commercial web service or isp or what ever that everyone say.
what's wrong with this code?
in util.py the ip should be public not private
import struct
from collections import namedtuple
def addr_from_args(args, host='**server's ip public**', port=9999):
if len(args) >= 3:
host, port = args[1], int(args[2])
elif len(args) == 2:
host, port = host, int(args[1])
else:
host, port = host, port
return host, port
def msg_to_addr(data):
ip, port = data.decode('utf-8').strip().split(':')
return (ip, int(port))
def addr_to_msg(addr):
return '{}:{}'.format(addr[0], str(addr[1])).encode('utf-8')
def send_msg(sock, msg):
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def recvall(sock, n):
# Helper function to recv n bytes or return None if EOF is hit
data = b''
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data
def recv_msg(sock):
# 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)
class Client(namedtuple('Client', 'conn, pub, priv')):
def peer_msg(self):
return addr_to_msg(self.pub) + b'|' + addr_to_msg(self.priv)

Sockets Programming with Video Streaming with python

I have to make a project where i accept multiple client connections and I have to send screenshots of the screen of the client to the server and show it on the screen and if I have to be able to stream clients screen to the server. How do I go about this? I've been trying to make this for about 2 months now. I am stuck and don't know how to make it.
Any reply is greatly appreciated.
This is the server code I have so far.
import threading
import socket
from queue import Queue
NUMBER_OF_THREADS = 2
JOB_NUMBER = [1,2]
queue = Queue()
class MultiServer(object):
#Initialize Server Object with host, port, socket, all connections and all the IP addresses
def __init__(self):
self.host = ""
self.port = 8965
self.socket = None
self.all_connections = []
self.all_addresses = []
self.all_users = []
#Create Socket
def socket_create(self):
#If socket creation fails except the error and show to the User and exit the program
try:
self.socket = socket.socket()
except socket.error as msg:
print("Socket creation failed, error: " +str(msg))
sys.exit(1)
#Use socket.setsockopt to keep reusing the same port
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return
def socket_bind(self):
#Bind socket to port and wait for incoming connections
try:
self.socket.bind((self.host, self.port))
self.socket.listen(5)
#Is binding the socket fails show error to the user and try again in 5 seconds
except socket.error as msg:
print("Socket binding error: " + str(msg))
time.sleep(5)
self.socket_bind()
return
def accept_connections(self):
#Accept Connections from multiple clients and save to list
#Close all old connections to prevent errors
for c in self.all_connections:
c.close()
self.all_connections = []
self.all_addresses = []
while True:
try:
conn, address = self.socket.accept()
conn.setblocking(1)
client_hostname = conn.recv(1024).decode("utf-8")
address= address + (client_hostname,)
except Exception as ex:
print('Error accepting connections: %s' %str(ex))
# Inifinite Loop
continue
self.all_connections.append(conn)
self.all_addresses.append(address)
print('\nConnection has been estalished: {0} ({1})'.format(address[-1], address[0]))
return
def send_commands(self):
while True:
cmd = input("$:")
if cmd == "list":
self.list_connections()
def list_connections(self):
""" List all connections """
results = ''
for i, conn in enumerate(self.all_connections):
try:
conn.send(str.encode(' '))
conn.recv(20480)
except:
del self.all_connections[i]
del self.all_addresses[i]
continue
results += str(i) + ' ' + str(self.all_addresses[i][0]) + ' ' + str(
self.all_addresses[i][1]) + ' ' + str(self.all_addresses[i][2]) + '\n'
print('----- Clients -----' + '\n' + results)
return
def create_workers():
server = MultiServer()
for i in range(2):
t = threading.Thread(target=work, args=(server,))
t.daemon = True
t.start()
def work(server):
while True:
x = queue.get()
if x == 1:
server.socket_create()
server.socket_bind()
server.accept_connections()
if x == 2:
server.send_commands()
queue.task_done()
return
def create_jobs():
for x in JOB_NUMBER:
queue.put(x)
queue.join()
def main():
create_workers()
create_jobs()
if __name__ == '__main__':
main()
And this is the Client code I have so far
import socket
class Client(object):
def __init__(self):
self.serverHost = '127.0.0.1'
self.serverPort = 8965
self.socket = None
def socket_create(self):
""" Create a socket """
try:
self.socket = socket.socket()
except socket.error as e:
print("Socket creation error" + str(e))
return
return
def socket_connect(self):
""" Connect to a remote socket """
try:
self.socket.connect((self.serverHost, self.serverPort))
except socket.error as e:
print("Socket connection error: " + str(e))
time.sleep(5)
raise
try:
self.socket.send(str.encode(socket.gethostname()))
except socket.error as e:
print("Cannot send hostname to server: " + str(e))
raise
return
def recieve_requests(self):
""" Controle of de server nog actief is """
try:
self.socket.recv(10)
except Exception as ex:
print("Couldn't recieve Commands: " + str(ex))
return
while True:
data = self.socket.recv(20480).decode("utf-8")
print(data)
print("mislukt")
client = Client()
client.socket_create()
def main():
client = Client()
client.socket_create()
try:
client.socket_connect()
except Exception as ex:
print(f"Socket connection error: {ex}")
while True:
try:
client.recieve_requests()
except Exception as ex:
print(ex)

SocketServer rfile.read() very very slow

I am building an HTTPS proxy which can forward all SSL traffic. It is called a transparent tunneling. Anyway, I have a problem with Python's socketserver. When I called rfile.read(), it takes a very long time to return. Even I used select to make sure the I/O is ready, it still takes a very long time. Usually 30s and the client's socket is closed because of timeout. I cannot make the socket unblocking, because I need to read the data first, and then forward all the data I just read to remote server, it must be returned with data first.
My code is following:
import SocketServer
import BaseHTTPServer
import socket
import threading
import httplib
import time
import os
import urllib
import ssl
import copy
from history import *
from http import *
from https import *
from logger import Logger
DEFAULT_CERT_FILE = "./cert/ncerts/proxpy.pem"
proxystate = None
class ProxyHandler(SocketServer.StreamRequestHandler):
def __init__(self, request, client_address, server):
self.peer = False
self.keepalive = False
self.target = None
self.tunnel_mode = False
self.forwardSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Just for debugging
self.counter = 0
self._host = None
self._port = 0
SocketServer.StreamRequestHandler.__init__(self, request, client_address, server)
def createConnection(self, host, port):
global proxystate
if self.target and self._host == host:
return self.target
try:
# If a SSL tunnel was established, create a HTTPS connection to the server
if self.peer:
conn = httplib.HTTPSConnection(host, port)
else:
# HTTP Connection
conn = httplib.HTTPConnection(host, port)
except HTTPException as e:
proxystate.log.debug(e.__str__())
# If we need a persistent connection, add the socket to the dictionary
if self.keepalive:
self.target = conn
self._host = host
self._port = port
return conn
def sendResponse(self, res):
self.wfile.write(res)
def finish(self):
if not self.keepalive:
if self.target:
self.target.close()
return SocketServer.StreamRequestHandler.finish(self)
# Otherwise keep-alive is True, then go on and listen on the socket
return self.handle()
def handle(self):
global proxystate
if self.keepalive:
if self.peer:
HTTPSUtil.wait_read(self.request)
else:
HTTPUtil.wait_read(self.request)
# Just debugging
if self.counter > 0:
proxystate.log.debug(str(self.client_address) + ' socket reused: ' + str(self.counter))
self.counter += 1
if self.tunnel_mode:
HTTPUtil.wait_read(self.request)
print "++++++++++++++++++++++++++"
req=self.rfile.read(4096) #This is the line take very lone time!
print "----------------------------------"
data = self.doFORWARD(req)
print "**************************************"
if len(data)!=0:
self.sendResponse(data)
return
try:
req = HTTPRequest.build(self.rfile)
except Exception as e:
proxystate.log.debug(e.__str__() + ": Error on reading request message")
return
if req is None:
return
# Delegate request to plugin
req = ProxyPlugin.delegate(ProxyPlugin.EVENT_MANGLE_REQUEST, req.clone())
# if you need a persistent connection set the flag in order to save the status
if req.isKeepAlive():
self.keepalive = True
else:
self.keepalive = False
# Target server host and port
host, port = ProxyState.getTargetHost(req)
if req.getMethod() == HTTPRequest.METHOD_GET:
res = self.doGET(host, port, req)
self.sendResponse(res)
elif req.getMethod() == HTTPRequest.METHOD_POST:
res = self.doPOST(host, port, req)
self.sendResponse(res)
elif req.getMethod() == HTTPRequest.METHOD_CONNECT:
res = self.doCONNECT(host, port, req)
def _request(self, conn, method, path, params, headers):
global proxystate
conn.putrequest(method, path, skip_host = True, skip_accept_encoding = True)
for header,v in headers.iteritems():
# auto-fix content-length
if header.lower() == 'content-length':
conn.putheader(header, str(len(params)))
else:
for i in v:
conn.putheader(header, i)
conn.endheaders()
if len(params) > 0:
conn.send(params)
def doRequest(self, conn, method, path, params, headers):
global proxystate
try:
self._request(conn, method, path, params, headers)
return True
except IOError as e:
proxystate.log.error("%s: %s:%d" % (e.__str__(), conn.host, conn.port))
return False
def doCONNECT(self, host, port, req):
#global proxystate
self.tunnel_mode = True
self.tunnel_host = host
self.tunnel_port = port
#socket_req = self.request
#certfilename = DEFAULT_CERT_FILE
#socket_ssl = ssl.wrap_socket(socket_req, server_side = True, certfile = certfilename,
#ssl_version = ssl.PROTOCOL_SSLv23, do_handshake_on_connect = False)
HTTPSRequest.sendAck(self.request)
#print "Send ack to the peer %s on port %d for establishing SSL tunnel" % (host, port)
print "into forward mode: %s : %s" % (host, port)
'''
host, port = socket_req.getpeername()
proxystate.log.debug("Send ack to the peer %s on port %d for establishing SSL tunnel" % (host, port))
while True:
try:
socket_ssl.do_handshake()
break
except (ssl.SSLError, IOError) as e:
# proxystate.log.error(e.__str__())
print e.__str__()
return
# Switch to new socket
self.peer = True
self.request = socket_ssl
'''
self.setup()
#self.handle()
def doFORWARD(self, data):
host, port = self.request.getpeername()
#print "client_host", host
#print "client_port", port
try:
print "%s:%s===>data read, now sending..."%(host,port)
self.forwardSocket.connect((self.tunnel_host,self.tunnel_port))
self.forwardSocket.sendall(data)
print data
print "%s:%s===>sent %d bytes to server"%(host,port,len(data))
select.select([self.forwardSocket], [], [])
chunk = self.forwardSocket.recv(4096)
print chunk
print "%s:%s===>receive %d bytes from server"%(host,port,len(chunk))
return chunk
except socket.error as e:
print e.__str__()
return ''
class ThreadedHTTPProxyServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
allow_reuse_address = True
class ProxyServer():
def __init__(self, init_state):
global proxystate
proxystate = init_state
self.proxyServer_port = proxystate.listenport
self.proxyServer_host = proxystate.listenaddr
def startProxyServer(self):
global proxystate
self.proxyServer = ThreadedHTTPProxyServer((self.proxyServer_host, self.proxyServer_port), ProxyHandler)
# Start a thread with the server (that thread will then spawn a worker
# thread for each request)
server_thread = threading.Thread(target = self.proxyServer.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.setDaemon(True)
proxystate.log.info("Server %s listening on port %d" % (self.proxyServer_host, self.proxyServer_port))
server_thread.start()
while True:
time.sleep(0.1)
This is driving me crazy, because when I forward normal HTTP traffic, the read() returns immediately with the data. But every time when the client sent SSL traffic (binary), the read() takes very long time to return! And I think there is some mechanics that the read() only returns when the request socket is closed by remote client. Does anyone know how to make the read() fast? I tried recv() and readline(), both of them is as slow as read() when handling binary traffic!
I had similar problem on my python server while trying to send image to it via http.
rfile.read took 1700ms for a 800kb image and 4500ms for a 4.5mb image. I was also doing this through a limited network speed on a vpn.
It appears that the rfile.read downloads/uploads the file. By improving connection/network speed between client-server i have reduced 1700ms read to less than 50ms.

Categories

Resources