Let gevent stop polling when one socket succeeds - python

I'm using gevent to poll several sockets just to see if one of the specified ports is open. How to make gevent stop polling if one of the sockets succeeds?
import gevent
from gevent import socket
vm_ip = "10.3.12.2"
ports = [22, 16120, 16122]
def fn(port):
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
result = s.connect_ex((vm_ip, port))
s.close()
if result == 0:
return
jobs = [gevent.spawn(fn, port) for port in ports]
gevent.joinall(jobs, timeout=30)

You can simply set a flag in your while loop, and turn off that flag when you found the result. Greenlets are coroutines, not threads, so no problem in doing this:
import gevent
from gevent import monkey
monkey.patch_all()
from gevent import socket
vm_ip = "10.3.12.2"
ports = [22, 16120, 16122]
found = False
def fn(port):
while not found:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
result = s.connect_ex((vm_ip, port))
s.close()
if result == 0:
found = True
return
jobs = [gevent.spawn(fn, port) for port in ports]
gevent.joinall(jobs, timeout=30)

Related

ThreadPoolExecutor Not Using Multiple Workers When Being Called Inside a Function

I'm trying to make a module that scans a given IP address and returns true or false for each port depending on it's current state. It works fine when the context manager is called by itself but when it's called within a function it stops using all of it's allocated threads. Here is my code:
import socket
import concurrent.futures
def _scan(ip, port):
scanner = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scanner.settimeout(1)
try:
scanner.connect((ip, port))
scanner.close()
return True
except:
return False
def portScan(ip, workers, portNum):
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
for port in range(portNum):
future = executor.submit(_scan, ip, port + 1)
print(future.result())
portScan("1.1.1.1", 100, 1000)
The problem is that you are waiting for each future to complete before submitting the next. You could use map instead. It will fan out the work to all of the threads and iterate the results in the same order as the parameters submitted.
import socket
import concurrent.futures
def _scan(params):
ip, port = params
scanner = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scanner.settimeout(1)
try:
scanner.connect((ip, port))
scanner.close()
return True
except:
return False
def portScan(ip, workers, portNum):
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
for result in executor.map(_scan, ((ip, port) for port in range(portNum))):
print(result)
portScan("127.0.0.1", 5, 22)

Show all the clients connected to a socket server and send them data

I have this simple code:
import socket
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind((host, port))
socket.listen()
while True:
client_socket, addr = socket.accept()
send = input("Send: ") # but I need a way to send it to all the clients connected
if send == "devices":
# here I'd have a list of all devices connected
client_socket.send(send.encode())
data = client_socket.recv(4096)
print (data)
As I wrote in the comments, I need a way to manage them all in one. How can I do? Maybe with _thread library?
You could mainitain a list of clients that can be passed to an external function that performs an action on all clients.
import socket
host = ''
port = 1000
max_connections = 5
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind((host, port))
socket.listen(max_connections)
clients = [] # Maintain a list of clients
try:
while True:
client_socket, addr = socket.accept()
clients.append(client_socket) #Add client to list on connection
i_manage_clients(clients) #Call external function whenever necessary
except KeyboardInterrupt:
socket.close()
def i_manage_clients(clients): #Function to manage clients
for client in clients:
client.send('Message to pass')
The above example demonstrates how send data to all clients at once. You could use the
import socket
from thread import *
host = ''
port = 1000
max_connections = 5
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind((host, port))
socket.listen(max_connections)
try:
while True:
client_socket, addr = socket.accept()
start_new_thread(i_manage_client, (client_socket,addr))
except KeyboardInterrupt:
socket.close()
def i_manage_client(client_socket, addr): #Function to manage clients
client_socket.send('Message to pass')
data = client_socket.recv(4096)
print(client_socket)
print(addr)
print(data)

Error: Transport endpoint is not connected (Python Sockets)

I'm trying to create a simple chat application using sockets in Python (with threads). Application is simple client has to threads one to send data and another to receive. Server has to two threads one to accept client connection and another to broadcast the message. But on running the below code, I'm getting error message
Transport endpoint is not connected
Can anybody tell me why I'm getting this error
Client
import socket, threading
def send():
msg = raw_input('Me > ')
cli_sock.send(msg)
def receive():
data = cli_sock.recv(4096)
print('> '+ str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5028
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
thread_send = threading.Thread(target = send)
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
Server
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
CONNECTION_LIST.append(cli_sock)
print('Client (%s, %s) connected' % cli_add)
def broadcast_data():
while True:
data = ser_sock.recv(4096)
for csock in CONNECTION_LIST:
try:
csock.send(data)
except Exception as x:
print(x.message)
cli_sock.close()
CONNECTION_LIST.remove(cli_sock)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5028
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
thread_bd = threading.Thread(target = broadcast_data)
thread_bd.start()
You're using server sockets incorrectly. You cannot recv on server sockets, instead you accept connections on them; accept returns the actual connection socket:
ser_sock.listen(1)
sock, addr = ser_sock.accept()
print('Got connection from {}'.format(addr))
# only this *connection* socket can receive!
data = sock.recv(4096)

Multiprocessing and sockets in Python

I am trying to make multiprocessing and socket programming work together, but, I am stuck at this point. Problem is that, I am getting this error:
File "multiprocesssockserv.py", line 11, in worker
clientsocket = socket.fromfd(clientfileno, socket.AF_INET, socket.SOCK_STREAM)
error: [Errno 9] Bad file descriptor
Complete code that causing the error is as following:
import multiprocessing as mp
import logging
import socket
logger = mp.log_to_stderr(logging.WARN)
def worker(queue):
while True:
clientfileno = queue.get()
print clientfileno
clientsocket = socket.fromfd(clientfileno, socket.AF_INET, socket.SOCK_STREAM)
clientsocket.recv()
clientsocket.send("Hello World")
clientsocket.close()
if __name__ == '__main__':
num_workers = 5
socket_queue = mp.Queue()
workers = [mp.Process(target=worker, args=(socket_queue,)) for i in
range(num_workers)]
for p in workers:
p.daemon = True
p.start()
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('',9090))
serversocket.listen(5)
while True:
client, address = serversocket.accept()
socket_queue.put(client.fileno())
edit: I am using socket.fromfd because I can't put sockets into a queue :) I need a way to access same sockets from different processes somehow. That is the core of my problem.
After working on this for a while, I decided to approach this problem from a different angle, and following method seems to be working for me.
import multiprocessing as mp
import logging
import socket
import time
logger = mp.log_to_stderr(logging.DEBUG)
def worker(socket):
while True:
client, address = socket.accept()
logger.debug("{u} connected".format(u=address))
client.send("OK")
client.close()
if __name__ == '__main__':
num_workers = 5
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('',9090))
serversocket.listen(5)
workers = [mp.Process(target=worker, args=(serversocket,)) for i in
range(num_workers)]
for p in workers:
p.daemon = True
p.start()
while True:
try:
time.sleep(10)
except:
break
I'm not an expert so I can't give the real explanation but if you want to use queues, you need to reduce the handle and then recreate it:
in your main :
client, address = serversocket.accept()
client_handle = multiprocessing.reduction.reduce_handle(client.fileno())
socket_queue.put(client_handle)
and in your worker:
clientHandle = queue.get()
file_descriptor = multiprocessing.reduction.rebuild_handle(client_handle)
clientsocket = socket.fromfd(file_descriptor, socket.AF_INET, socket.SOCK_STREAM)
also
import multiprocessing.reduction
That will work with your original code.
However, I am currently having problems with closing sockets in worker processes after they were created as I described.
Here is some working code on what's mentioned above - https://gist.github.com/sunilmallya/4662837 multiprocessing.reduction socket server with parent processing passing connections to client after accepting connections

simple server with multiple clients

I'm trying to implement simple server with multiple clients. It should receive data from necessary socket, process and then send data to other clients. I use select module from Python standard library.
Here's server:
class ProcessingServer:
def __init__(self, bindaddress="localhost", portname=50001, maxqueue=5):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((bindaddress, portname))
self.socket.listen(maxqueue)
self.inputsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.data = ""
def connect_to_output(self, address, port):
self.inputsocket.connect((address, port))
def start(self):
rsocks = []
wsocks = []
rsocks.append(self.socket)
wsocks.append(self.inputsocket)
self.socket.accept()
while True:
try:
reads, writes, errs = select.select(rsocks, wsocks, [])
except:
return
for sock in reads:
if sock == self.socket:
client, address = sock.accept()
rsocks.append(client)
else:
self.socket.send(self.data)
rsocks.remove(sock)
for sock in writes:
if sock == self.inputsocket:
self.data = sock.recv(512)
wsocks.remove(sock)
print repr(self.data)
Here's simple client:
import socket
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket.connect(("localhost", 50001))
while True:
data = mysocket.recv(512)
print repr(data)
mysocket.close()
Receiving part of server works fine, but server doesn't produce any output.
I'm not experienced in network programming at all and It feels like I'm missing something.
There are a few things that seem odd in your script.
The standard usage of the select module is the following: you have one socket to listen to connections, and one socket per connection with the clients.
At first, only this socket is added to your potential readers list and your potential writers list is empty.
Calling select.select(potential_readers, potential_writers, potential_errors) will return 3 lists:
- Sockets ready for reading
- Sockets ready for writing
- Sockets in error
In the list of sockets ready for reading, if the socket is the one listening for the connection, it must accept it and put the new socket in the potential reads, potential writes and potential errors.
If the socket is another one then, there is data to read from this socket. You shoud make a call to sock.recv(length)
If you want to send data, you should send it from your wlist returned by select.select.
The errlist is not used very often.
Now, for the solution for your problem, the way you describe your protocol (if I understood well), it might look like this:
import socket, select
sock_producer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_producer.bind(('localhost', 5000))
sock_producer.listen(5)
producers = []
clients = []
sock_consumer_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Note: different port to differentiate the clients who receive data from the one who sends messages
sock_consumer_listener.bind(('localhost', 5001))
rlist = [sock_producer, sock_listener]
wlist = []
errlist = []
out_buffer = []
while True:
r, w, err = select.select(rlist, wlist, errlist)
for sock in r:
if sock == sock_producer:
prod, addr = sock.accept()
producers.append(prod)
rlist.append(prod)
elif sock == sock_consumer_listener:
cons, addr = sock.accept()
clients.append(cons)
wlist.append(cons)
else:
out_buffer.append(sock.recv(1024))
out_string = ''.join(out_buffer)
out_buffer = []
for sock in w:
if sock in clients:
sock.send(out_string)
I haven't tested this code so there might be a few errors, but this is close to how I would do it.
Yeah...use zeromq instead:
server.py
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://127.0.0.1:50001")
while True:
msg = socket.recv()
print "Got", msg
socket.send(msg)
client.py
import zmq
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:50001")
for i in range(100):
msg = "msg %s" % i
socket.send(msg)
print "Sending", msg
msg_in = socket.recv()

Categories