I'm trying to write a very simple Port Scanner in Python, and it was working great until I decided to introduce threading, in order to speed things up.
I want to include a brief summary at the end, which lists the ports that are open. I've put this in a function called finish. However, since introducing threading, that summary appears as the first line in the output of my code, no matter where I put it.
Is there a way I can effectively confine threading to the functions I need it for, and then turn it off before it gets to the summary/finish(), or am I just making an obvious mistake? Any help would be much appreciated.
Code:
from socket import *
from threading import *
screenLock = Semaphore(value=1)
open_ports = []
def scan(ip,port):
try:
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip, port))
screenLock.acquire()
print ('Scanning ', ip , 'on port', port)
print("Port",port, "is open")
s.close()
summary(port)
except:
screenLock.acquire()
print ('Scanning ', ip , 'on port', port)
print("Port",port,"is closed")
finally:
screenLock.release()
s.close()
def loop():
for i in range(1,100):
ip = '192.168.0.38'
port = int(i)
t = Thread(target=scan, args=(ip,int(port)))
t.start()
return
def summary(port):
global open_ports
open_ports.append(port)
return
def main():
loop()
finish()
def finish():
print('The following ports are open:',open_ports)
main()
You have to wait for all the Threads to finish:
def loop():
threads = []
for i in range(1,100):
ip = '192.168.0.38'
port = int(i)
t = Thread(target=scan, args=(ip,int(port)))
t.start()
threads.append(t)
[t.join() for t in threads]
Related
I have a button that is supposed to stop a thread that is running a server function on another Python file. The solutions I've tried are as follows:
Solution #1: Threading.Event
mainmenu.py
import server as serv #as in server.py
import socket
from threading import Thread
import customtkinter as cust
class GUI2(cust.CTk): #second window; not the root
def __init__(self):
self.master2 = cust.CTkToplevel()
self.master2.title("Admin/Host Lobby")
self.master2.geometry(f"{906}x{400}")
self.master2.protocol("WM_DELETE_WINDOW", self.leavewindow)
self.leave = cust.CTkButton(self.master2, text = "Leave", fg_color = "Red", text_color = "White", hover_color = "Maroon", command = lambda: self.leavewindow())
self.leave.grid(row = 0, column = 0, sticky = "n", padx = 1, pady = 1)
self.thread = Thread(target = serv.startChat)
self.thread.start()
def leavewindow(self):
serv.terminate() #calls function from server.py that sets flag to true
self.thread.join() #wait for thread to close
print("Thread closed")
serv.commence() #calls function from server.py that sets flag to false in case window is accessed again without exiting the program
self.master2.destroy()
server.py
import socket
import threading
import traceback
flag = threading.Event()
PORT = 5000
SERVER = socket.gethostbyname(socket.gethostname())
ADDRESS = (SERVER, PORT)
FORMAT = "utf-8"
clients, names = [], []
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDRESS)
def terminate(): #set flag to true
flag.set()
def commence(): #set flag to false
flag.clear()
def startChat(): #function that listens for client connections; the aforementioned function I want to stop/break when button is pressed
print("server is working on " + SERVER)
server.listen(30)
try:
while not flag.is_set(): #function runs as long as flag is not true
conn, addr = server.accept()
name = conn.recv(1024).decode(FORMAT)
clients.append(conn)
except:
print (traceback.format_exc())
Solution #2: Global Flag Variable
Same code as above but with the following changes:
mainmenu.py
def leavewindow(self):
serv.setFlag(1) #passes integer 1 to set flag to True
self.thread.join() #wait for thread to close
print("Thread closed")
serv.setFlag(0) #passes integer 0 to set flag to false in case window is accessed again without exiting the program
self.master2.destroy()
server.py
flag = False
def setFlag(a): #function receives integer to set flag value
global flag
if a == 0:
flag = False
else:
flag = True
def startChat(): #function that listens for client connections; the aforementioned function I want to stop/break when button is pressed
print("server is working on " + SERVER)
server.listen(30)
try:
while True:
global flag
if flag:
break
else:
conn, addr = server.accept()
name = conn.recv(1024).decode(FORMAT)
clients.append(conn)
except:
print (traceback.format_exc())
Both of these "solutions" ends up freezing the window for an indefinite time; no errors printed in the terminal plus the line print("Thread closed") isn't even reached.
Any advice or alternative solutions in fixing this bug is highly appreciated.
A (if not the) major cause of an unresponsive tkinter GUI is a callback that keeps running.
The only callback that we see is leavewindow().
In that function, basically only self.thread.join() can cause this.
By default, sockets are created in blocking mode.
So for example recv will wait until it receives data.
Which is not what you want, because your flag or event will not be tested until after data is received.
You could set a timeout on the conn socket so it raises an exception when no data is received.
In the handler for that exception, just sleep() in the while-loop for some milliseconds.
def startChat(): #function that listens for client connections; the aforementioned function I want to stop/break when button is pressed
print("server is working on " + SERVER)
server.listen(30)
# Not sure if the following line is needed...
server.settimeout(0.005) # time out after 5 ms.
try:
while not flag.is_set(): # works with global flag as well
conn, addr = server.accept()
conn.settimeout(0.005) # time out after 5 ms.
name = conn.recv(1024).decode(FORMAT)
clients.append(conn)
except socket.timeout:
time.sleep(0.005)
except Exception:
print (traceback.format_exc())
Or you could use the selectors module with a nonblocking socket to only try and read data if any is available. Here you should also sleep() in the while-loop for some milliseconds when no data is available.
This question already has an answer here:
thread starts running before calling Thread.start
(1 answer)
Closed 2 years ago.
I am trying to run a thread within a thread. When I execute monitor.startMonitoring(), it gets stuck in that function, specifically on threading.Thread(target=self._startMonitoring(), daemon=True).start().
What can I do so I can go to the last line (print function call) of the code?
host = '127.0.0.1'
port = 9000
def _receiveHealthMsg(clientsock, clientaddr):
try:
while True:
print(f'{clientaddr} : {clientsock.recv(1024).decode("utf-8")}: '
f'{datetime.datetime.now().isoformat()}')
except ConnectionResetError:
print("Connection has been severed")
class Monitor:
def __init__(self, host, port):
self._sock = socket.socket()
self._sock.bind((host, port))
self._sock.listen(5)
self._threads = []
self._clients = []
def startMonitoring(self):
threading.Thread(target=self._startMonitoring(), daemon=True).start()
def _startMonitoring(self):
while True:
c, addr = self._sock.accept()
thread = threading.Thread(target=_receiveHealthMsg, args=(c, addr))
thread.start()
self._threads.append(thread)
self._clients.append((c, addr))
monitor = Monitor(host, port)
monitor.startMonitoring()
print('do some stuff here while threads are running')
You called _start_monitoring, you didn't pass it as a function to run. Change the line to:
threading.Thread(target=self._startMonitoring, daemon=True).start()
# ^ parentheses removed
I'm trying to run several sockets on different ports as the following:
Socket:
import socket
class Receiver:
TCP_IP = '127.0.0.1' # by default
TCP_PORT = 1999 # by default
BUFFER_SIZE = 1024
def __init__(self, TCP_IP, TCP_PORT):
self.TCP_IP = TCP_IP
self.TCP_PORT = TCP_PORT
def initialize(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((self.TCP_IP, self.TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print('Connection address:', addr)
while 1:
data = conn.recv(self.BUFFER_SIZE)
if not data: break
rdata = 'U'.encode() + data
print("received data:", data[1:5])
conn.send(rdata[0:5]) # echo
conn.close()
And Runner:
from NVGEmulator.Receiver import Receiver
import threading
class FireStarter:
def starter(self):
nvgEmu1 = Receiver('127.0.0.1', 2999)
print("FIRST INITIALIZED")
nvgEmu1.initialize()
nvgEmu2 = Receiver('127.0.0.1', 2998)
nvgEmu2.initialize()
print("SECOND INITIALIZED")
def starter_second(self):
nvgEmu2 = Receiver('127.0.0.1', 2998)
print("SECOND INITIALIZED")
nvgEmu2.initialize()
if __name__ == '__main__':
print("Receiver has been started")
fs = FireStarter()
thr = threading.Thread(target=fs.starter())
thr.start()
thr.join()
thr2 = threading.Thread(target=fs.starter_second())
thr2.start()
When I run FireStarter, it runs only the first instance of socket. I've read that there is "threading" library which can run several processes in async, but anyway there is no result, cause in console I see that "FIRST INITIALIZED". How to run the second or the third socket listener? May be there is another approach to do this.
You have two problems in that code.
The first one: here the second socket is waiting for the first one to end as it is trapped in the while loop:
def starter(self):
nvgEmu1 = Receiver('127.0.0.1', 2999)
print("FIRST INITIALIZED")
nvgEmu1.initialize()
nvgEmu2 = Receiver('127.0.0.1', 2998)
nvgEmu2.initialize()
print("SECOND INITIALIZED")
The second one is this join sentence thr.join(), with that you are forcing the second thread to wait for the first one, avoiding to run it in parallel.
Probably the approach I would follow is spawning a thread within the initialize function inside your Receiver class and manage the thread there (maybe extending the Thread class), with that you avoid to spawn by yourself a new thread each time and you have your code more encapsulated.
I'm working on a threading server in Python but I'm running into problems with one connection blocking. When I make the first connection, it sleeps and then I don't get anything back on the second connection to the server until the first is done sleeping. Any thoughts on what I'm doing wrong?
import socket, ssl, time, threading
def test_handler(conn):
print "sleeping 10 seconds"
time.sleep(10)
conn.write("done sleeping")
return 0
class ClientThread(threading.Thread):
def __init__(self, connstream):
threading.Thread.__init__(self)
self.conn = connstream
def run(self):
test_handler(self.conn)
threads = []
bindsocket = socket.socket()
bindsocket.bind(('0.0.0.0', 10023))
bindsocket.listen(10)
while True:
newsocket, fromaddr = bindsocket.accept()
connstream = ssl.wrap_socket(newsocket,
server_side=True,
certfile="server.crt",
keyfile="server.key",
ssl_version=ssl.PROTOCOL_TLSv1)
try:
c = ClientThread(connstream)
c.start()
threads.append(c)
finally:
for t in threads:
t.join()
It blocks because you're joining your new thread (and all the others) after each new connection is established. join blocks until the thread terminates, so only call it when you actually want to wait until the thread is done.
Based on #Steve Trout's insight -- here is the modified code. It starts a thread when a client connects, but doesn't join until the end of the server. It also has more extensive logging.
source
import logging, socket, ssl, sys, time, threading
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)-4s %(threadName)s %(message)s",
datefmt="%H:%M:%S",
stream=sys.stderr,
)
def test_handler(conn):
logging.info("sleeping 1 second")
time.sleep(1)
conn.send("done sleeping\n")
return 0
class ClientThread(threading.Thread):
def __init__(self, connstream):
threading.Thread.__init__(self)
self.conn = connstream
def run(self):
test_handler(self.conn)
def main():
port = 10023
bindsocket = socket.socket()
bindsocket.bind(('0.0.0.0', port))
bindsocket.listen(10)
logging.info('listening on port %d', port)
while True:
newsocket, fromaddr = bindsocket.accept()
logging.info('connect from %s', fromaddr)
connstream = newsocket
if 0:
connstream = ssl.wrap_socket(
newsocket,
server_side=True,
certfile="server.crt",
keyfile="server.key",
ssl_version=ssl.PROTOCOL_TLSv1)
ClientThread(connstream).start()
logging.info('stop')
if __name__=='__main__':
main()
# make sure all threads are done
for th in threading.enumerate():
if th != threading.current_thread():
th.join()
In Python 3.3.3, i create a thread to listen some connection to the socket.It likes this:
import threading
import socket
import time
Host = ''
Port = 50000
flag = False
class ServerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def run(self):
try:
self._sock.bind((Host, Port))
self._sock.listen(5)
while True:
conn, addr = self._sock.accept()
print('Connected by', addr)
except socket.error as msg:
print(msg)
except Exception as e:
print(str(e))
finally:
self._sock.close()
def exit(self):
self._sock.close()
def TargetFunc(vlock):
vlock.acquire()
flag = True
vlock.release()
def main():
sthread = ServerThread()
sthread.start()
vlock = threading.Lock()
time.sleep(10)
vthread = threading.Thread(target = TargetFunc, args = (vlock, ))
vthread.start()
while True:
vlock.acquire()
if flag:
sthread.exit()
vlock.release()
break
vlock.release()
sthread.join()
vthread.join()
if __name__ == '__main__':
main()
There are two threads, one is listening socket, the other is to set a flag. When the flag is True, close the socket, then raise a socket error and catch it, so the listening socket terminates.But why it does not work this.
Thanks!
self._sock.accept() is blocking. So it will wait until somebody connects. You should use a nonblocking variant (or blocking but with a time-out). So that you can check the exit conditions.
Alternatively you could force an exception in the ServerThread.