How do I allow more simultaneous socket connections? - python

I'm attempting to implement the Reactor pattern in Python. I think I have a pretty decent start using multiprocessing and select.select. However, I'm trying to stress-test my server, so I wrote a simple DoS client to flood it with connections. But I get an interesting error:
[WinError 10061] No connection could be made because the target machine actively refused it
The interesting thing about this is that I'm doing socket.listen(5) for the backlog amount on the server. After I get readers ready from select.select I display the count, and I only ever have 1 or 2 - not the 5 that I would expect.
For a small number of threads (~20) I haven't noticed it choke, but for a larger number (50+) it does tend to refuse connections.
Is my problem on the server or client side (or just at the OS/socket level)? Is this a problem that I can fix? And if so, how?
Here is my code:
Client
import threading
import time
import socket
from contextlib import contextmanager
IP = '127.0.0.1'
PORT = 4200
#contextmanager
def open_socket(ip, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((ip, port))
yield sock
finally:
sock.close()
class Flood(threading.Thread):
def __init__(self, id):
super(Flood, self).__init__()
self.id = id
self.failed = False
def run(self):
try:
with open_socket(IP, PORT) as sock:
msg = "Hello this is some data from %d" % self.id
sock.send(msg.encode())
except Exception as e:
print(e)
self.failed = True
def make_threads(count):
return [Flood(_) for _ in range(count)]
threads = make_threads(5000)
start = time.time()
for t in threads:
t.start()
for t in threads:
t.join()
print("Failed: ", sum(1 if x.failed else 0 for x in threads))
print("Done in %f seconds" % (time.time() - start))
Server
import sys
import logging
import socket
import select
import time
import queue
from multiprocessing import Process, Queue, Value
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
log.addHandler(logging.StreamHandler())
IP = '127.0.0.1'
PORT = 4200
keep_running = True
def dispatcher(q, keeprunning):
try:
while keeprunning:
val = None
try:
val = q.get(True, 5)
if val:
log.debug(val[0].recv(1024).decode())
val[0].shutdown(socket.SHUT_RDWR)
val[0].close()
except queue.Empty:
pass
log.debug("Dispatcher quitting")
except KeyboardInterrupt:
log.debug("^C caught, dispatcher quitting")
def mainloop(sock):
readers, writers, errors = [sock], [], []
timeout = 5
while True:
readers, writers, errors = select.select(readers,
writers,
errors,
timeout)
incoming = yield readers, writers, errors
if incoming and len(incoming) == 3:
readers, writers, errors = incoming
if not readers:
readers.append(sock)
def run_server():
keeprunning = Value('b', True)
q = Queue()
p = Process(target=dispatcher, args=(q, keep_running))
try:
p.start()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((IP, PORT))
sock.listen(50)
sock.setblocking(0)
loop = mainloop(sock)
for readers, writers, errors in loop:
if readers:
client, addr = readers[0].accept()
q.put((client, addr))
log.debug('*'*50)
log.debug('%d Readers', len(readers))
log.debug('%d Writers', len(writers))
log.debug('%d Errors', len(errors))
except KeyboardInterrupt:
log.info("^C caught, shutting down...")
finally:
keeprunning.value = False
sock.close()
p.join()
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: test.py (client|server)")
elif sys.argv[1] == 'client':
run_client()
elif sys.argv[1] == 'server':
run_server()

I tried to test your code, but failed on import queue.
Nevertheless, it might be that
your OS acts as the listen() function is specified: "Implementations may impose a limit on backlog and silently reduce the specified value."
your OS stops accepting the connection as soon there are enough incomplete connections, which might not be displayed upon request.
These are just guesses about what might be the reason; maybe I am completely wrong.

Related

Sending and receiving using sockets python

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.')

Audio Stream ends up with additional chriping and noise in TCP server written in python

We are working on a mobile app where we have a server on python3 and are accommodating the streams through this server.
But when android clients connect to the server the voice is heard with 5 seconds of delay or so and also becomes too much noisy and contains chirping, we have our best on the server side and android side, need someone to guide through the way.
Here is the code for instance:
import socket
import time
from threading import Thread
from multiprocessing.dummy import Pool as ThreadPool
class VoiP(Thread):
def __init__(self):
Thread.__init__(self)
def server_start(self, TCP_IP = '0.0.0.0', TCP_PORT = 2004 ,BUFFER_SIZE = 1024, Connections = 4):
self.Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.Server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.Server.bind((TCP_IP, TCP_PORT))
self.Server.listen(Connections)
print("Server is starting.")
def client_connection(self):
try:
print("Waiting for Room1 Client A \n")
(self.Room1a, address) = self.Server.accept()
print (type(self.Room1a))
print("Room1 Client A connected \n")
print("Waiting for Room1 Client B \n")
(self.Room1b, address) = self.Server.accept()
print("Room1 Client B connected \n")
print("Waiting for Room2 Client A \n")
(self.Room2a, address) = self.Server.accept()
print("Room2 Client A connected \n")
print("Waiting for Room2 Client B \n")
(self.Room2b, address) = self.Server.accept()
print("Room2 Client B connected \n")
print("Print All clients connected")
except Exception as e:
print("Error While Connecting to client")
def byte_logic(self, byte, data):
if byte is not b'':
data = byte + data
byte = b''
if len(data) % 2 is not 0:
byte = (data[-1])
data = data[0:-1]
return np.frombuffer(data, np.int16), byte
This is the adder to add client voices
def array_adder(self, a, b):
if len(a) < len(b):
c = b.copy()
c[:len(a)] += a
else:
c = a.copy()
c[:len(b)] += b
return bytes(c)
def room1a_transcev(self):
while True:
try:
self.data1a = self.Room1a.recv(2048)
self.np_r1a, self.extra_byte_1 = self.byte_logic(self.extra_byte_1, self.data1a)
self.room1_stream = self.array_adder(self.np_r1a, self.np_r1b)
self.Room2a.sendall(self.room1_stream)
self.Room2b.sendall(self.room1_stream)
except Exception as e:
print(e, "room1a_transcev error")
def room1b_rec(self):
while True:
try:
self.data1b = self.Room1b.recv(2048)
self.np_r1b, self.extra_byte_2 = self.byte_logic(self.extra_byte_2, self.data1b)
except Exception as e:
print(e, "room1b_transcev error")
def room2a_transcev(self):
while True:
try:
self.data2a = self.Room2a.recv(2048)
self.np_r2a, self.extra_byte_3 = self.byte_logic(self.extra_byte_3, self.data2a)
self.room2_stream = self.array_adder(self.np_r2a, self.np_r2b)
self.Room1a.sendall(self.room2_stream)
self.Room1b.sendall(self.room2_stream)
except Exception as e:
print(e, "room2a_transcev error")
def room2b_rec(self):
while True:
try:
self.data2b = self.Room2b.recv(2048)
self.np_r2b, self.extra_byte_4 = self.byte_logic(self.extra_byte_4, self.data2b)
except Exception as e:
print(e, "room2b_rec error")
if __name__ == "__main__":
objVOIP = VoiP()
objVOIP.server_start()
objVOIP.client_connection()
# asyncio.run(objVOIP.main())
thread1 = Thread(target=objVOIP.room1a_transcev)
thread2 = Thread(target=objVOIP.room1b_rec)
thread3 = Thread(target=objVOIP.room2a_transcev)
thread4 = Thread(target=objVOIP.room2b_rec)
thread1.setDaemon = True
thread2.setDaemon = True
thread3.setDaemon = True
thread4.setDaemon = True
thread1.start()
thread2.start()
thread3.start()
thread4.start()
I need the ideal case where there are minimal delay and noise. And mixing of two voices.
Well, this is a complex matter and I can't give a definitive answer, but I can give some tips.
First, this is called jitter, and usually happens when packets are not received in order or some of them take more time than others. So:
First, discard network problems by executing a test with local connections only, or in a controlled network where you know there is no traffic. I guess you have already done this.
Second, consider using UDP instead of TCP. Yeah, UDP can lose some packets if the network is busy and you have to control yourself their order (they can be received in a different order that they are sent, you will have to put an order number and reorder if necessary), but it's waaaay faster than TCP, and in a call it isn't really that important if a millisecond or two of audio are lost.
And third: For audio processing make sure you are using the C bind functions of your library correctly. That can make a huge difference in performance.

P2P Network: Python sockets not receiving data from other nodes

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)

Runtime error can not start new thread

I am trying to check if data is available on one port. If this it is avaiable then a message "yes" should be sent to another port and "no" if there is no data.
A client is connecting to that port where "yes" or "no" is coming. I run the script and every thing looked fine. But after one hour I got the error:
Runtime error can not start new thread. Exception in Thread 11:
Traceback< most recent call last: file threading.py line 914 in boot strap-inner.
I am new to python and I really do not understand what is going on. My code contains many threads as I am checking data from 10 ports and sending "yes" or "no" message to other 10 ports.
Here is a part of my code for 1 port:
import time
import socket
import threading
from threading import Thread
import select
#-----------------------------------Server --------------------------
s = socket.socket(socket.AF_INET) #Socket
h = '127.0.0.1' #Host where data coming from
p = 14201 #Port
halarm = "127.0.0.1" # A port will be opened to send availabilty status
palarm = 14202 # Port
def Server ():
while True:
try:
time.sleep(0.1)
s.connect((h, p))
except socket.error:
pass
#-----------------------------------Server/Client -------------------------------
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind((halarm, palarm)) # Bind to the Port where
sock.listen(1)
def func(conn): # Server-Client Function
while True:
try:
global s
Timeout = select.select([s], [], [], 5)# Timeout in seconds
connected = True
while True:
try:
if Timeout[0]:
conn.send(bytes("yes", "utf-8"))
time.sleep(3)
else:
conn.send(bytes("no", "utf-8"))
time.sleep(3)
newConnection= False
while not newConnection:
try:
s = socket.socket(socket.AF_INET)
s.connect((h, p))
Timeout = select.select([s], [], [], 5)# Timeout in seconds
newConnection= True
except socket.error:
conn.send(bytes("Port is closed", "utf-8"))
time.sleep(3)
pass
except socket.error:
pass
except:
pass
def connThread():
while True:
conn, addr = sock.accept()
time.sleep(0.1)
Thread(target = func, args=(conn,)).start()
if __name__ == '__main__':
Thread(target = Server).start()
Thread(target = connThread).start()
How can I solve this problem ? I appreciate all your help.

Python socket can't receive data

I'm writing interprocess communication using localhost sockets in Python 3.2 and testing it on Windows. Here is some test code with a server and a client, sending messages to each other. Strangely, it fails randomly with the RuntimeError error, raised in the receive function, somewhere around the 5th or 10th connection.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
import pickle
import time
import logging
from multiprocessing import Process
def receive(conn):
def ensure_receive(length):
parts = []
received = 0
while received < length:
chunk = conn.recv(length - received)
if not chunk:
raise RuntimeError("Connection broken")
parts.append(chunk)
received += len(chunk)
return b''.join(parts)
lengthString = ensure_receive(8)
serialized = ensure_receive(int(lengthString))
return pickle.loads(serialized)
def send(conn, message):
def ensure_send(message):
sent = 0
while sent < len(message):
sent += conn.send(message[sent:])
# logging.warning("Now sending")
serialized = pickle.dumps(message, 1)
messageLength = len(serialized)
ensure_send("{:8}".format(messageLength).encode('Latin-1'))
ensure_send(serialized)
def client_function(clientLimit):
for index in range(1, clientLimit + 1):
print ("Client", index)
try:
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect(('localhost', 12333))
send(conn, list(range(100000)))
message = receive(conn)
send(conn, list(range(100)))
# time.sleep(0.01)
conn.shutdown(socket.SHUT_WR)
conn.close()
except Exception:
logging.exception("Socket error in client")
def server_function(clientLimit):
newSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
newSocket.bind(('localhost', 12333))
newSocket.listen(16)
for _ in range(clientLimit):
(conn, address) = newSocket.accept()
time.sleep(0.01)
message = receive(conn)
send(conn, list(range(10)))
message = receive(conn)
conn.shutdown(socket.SHUT_WR)
conn.close()
def test(clientLimit):
server = Process(target = server_function, args = (clientLimit,))
server.start()
time.sleep(1)
client = Process(target = client_function, args = (clientLimit,))
client.start()
client.join()
server.join()
if __name__ == "__main__":
test(100)
However, there are no errors if I uncomment time.sleep(0.01) in client_function, or if I change message order a bit.
Is there a way to make it work, without putting in random waits, and allowing for arbitrary protocols?
It is because of conn.shutdown(socket.SHUT_WR) in your server_function. What you need is socket.SHUT_RD, or better yet, get rid of the shutdown() call at all.

Categories