I am trying to run a thread more than once and keep getting an error:
RuntimeError: threads can only be started once
I have tried reading up multithreading and implementing it in my code without any luck.
Here is the function I am threading:
def receive(q):
host = ""
port = 13000
buf = 1024
addr = (host,port)
Sock = socket(AF_INET, SOCK_DGRAM)
Sock.bind(addr)
(data, addr) = Sock.recvfrom(buf)
q.put(data)
Here is the code I want to run:
q = Queue.Queue()
r = threading.Thread(target=receive, args=(q,))
while True:
r.start()
if q.get() == "stop":
print "Stopped"
break
print "Running program"
When the stop message gets sent, the program should break out of the while loop, but it does not run due to multithreading. The while loop should constantly print out Running program, until the stop message is sent.
The queue is used to receive the variable data from the receive function (which is the stop).
Here is a working example (for python 2.7).
The program has two modes of operation:
with no arguments it runs the receive loop
with arguments it sends a datagram
Note how r.start() and r.terminate() are called outside of the while loop in client.
Also, receive has a while True loop.
import sys
import socket
from multiprocessing import Process, Queue
UDP_ADDR = ("", 13000)
def send(m):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(m, UDP_ADDR)
def receive(q):
buf = 1024
Sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Sock.bind(UDP_ADDR)
while True:
(data, addr) = Sock.recvfrom(buf)
q.put(data)
def client():
q = Queue()
r = Process(target = receive, args=(q,))
r.start()
print "client loop started"
while True:
m = q.get()
print "got:", m
if m == "stop":
break
print "loop ended"
r.terminate()
if __name__ == '__main__':
args = sys.argv
if len(args) > 1:
send(args[1])
else:
client()
I think the problem is once the thread is started, calling thread.start() again throws the error.
Using a try block would might work as a simple fix:
while True:
try:
r.start()
except Exception:
#or except RunTimeError:
pass
if q.get() == "stop":
print "Stopped"
break
print "Running program"
Related
Output at console server
I am trying to write bi-directional UDP communication using multithread but it crashes after sending two messages. Also i am new to threading so please post your solution on this.
Thanks
Server side:
import threading
from threading import Thread
import socket
from socket import *
import time
import pymongo
from datetime import datetime
from time import ctime
#broadcast works for this program
import netifaces
import os
import re
import struct
class cont():
def get_msg(self):
UDP = "192.168.1.27"
port = 4343
address = UDP, port
self.sock = socket(AF_INET, SOCK_DGRAM)
self.sock.bind(address)
while True:
r = self.sock.recvfrom(1000)
print("controller1: %s" % (r[0]))
reply = input('Main controller : ')
client_address = r[1]
self.sock.sendto(bytearray(reply, "utf-8"), client_address)
t2 = threading.Thread(target=self.get_msg, args=(reply,))
t2.start()
if __name__=='__main__':
c=cont()
#c.broad(msg="")
c.get_msg()
Client side:
UDP=""
port=4343
address=UDP,port
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while(True):
msg=input("Controller1")
client.sendto(bytearray(msg,"utf-8"),address)
reply=client.recvfrom(1000)
recved=str(reply)
print("Main Controller:% s" % recved))
Output required :
Server Console:
Client:b'hello'
Server:b'hi
Client Console:
Client: b'hello'
Server : (b'hi',('ip',port)
Here is a TCP class I made for communicating with my robots, can be easily modified for UDP. Might seem like a lot of code, but it's what it takes for "reliable" "two way" communication, without blocking your main program. I use processes instead of threads because threads in python aren't "real" threads due to the global interpreter lock.
import socket
from multiprocessing import Process, Queue, Event, Value
import traceback
class SocketComm(object):
def __init__(self,port):
self.address = ""
self.otherAddress = object
self.port = port
self.finished = Value("b", True)
self.inbox = Queue()
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.getMessagesProcess = Process(target=self.getMessages)
self.getMessagesProcess._stop_event = Event()
self.getMessagesProcess.daemon = True
self.connected = False
self.timeout = 3
return
def setupLine(self, addr):
self.address = addr
if self.address is "": #i.e. server on raspberry pi
try:
self.connection.settimeout(self.timeout)
self.connection.bind((self.address, self.port))
print("binding with port: " + str(self.port))
self.connection.listen(1)
self.connection, self.otherAddress = self.connection.accept()
print("connected to client at: " + self.otherAddress[0])
except socket.error as e:
print(str(e))
return False
else:
try:
#print("connecting to port: " + str(self.port))
self.connection.connect((self.address, self.port)) # i.e. client
print("connected to server")
except socket.error as e:
#print(str(e))
return False
self.getMessagesProcess.start()
self.connected = True
self.finished.value = False
print("inbox at: " + str(id(self.inbox)))
return True
def sendMessage(self, msg):
try:
self.connection.send(str.encode(msg))
#print("sent: " + str(msg))
except Exception as e:
pass
#print(str(e))
#traceback.print_exc()
#print("exception caught.")
return
def getMessages(self):
#print("getting messages now")
self.connection.settimeout(1)
while(not self.finished.value):
#print("checking inbox")
#print("inbox length: " + str(len(self.inbox)))
try:
received = self.connection.recv(1024)
decoded = received.decode('utf-8')
if len(decoded) > 0:
if(decoded == "end"):
self.finished.value = True
else:
self.inbox.put(decoded)
print("received: " + str(decoded))
except socket.error as e:
if(type(e).__name__ == "timeout"):
pass
else:
print("endpoint closed.")
self.finished.value = True
return
def closeConnection(self):
if(self.connected):
self.finished.value = True
self.getMessagesProcess._stop_event.set()
self.sendMessage("end")
try:
self.getMessagesProcess.join()
except:
print("process already finished.")
self.connection.close()
return
##
##if(__name__ == "__main__"):
## robotClient = SocketComm(5555)
## robotClient.setupLine("127.0.0.1")
## while(robotClient.finished.value == False):
## val = input("enter something: ")
## if(len(val) > 0):
## robotClient.sendMessage(val)
##
##
##if(__name__ == "__main__"):
## try:
## robotServer = SocketComm(5555)
## print("waiting for client to connect...")
## robotServer.setupLine("")
## print("connected!")
## while(robotServer.finished.value == False):
## val = input("enter something: ")
## if(len(val) > 0):
## robotServer.sendMessage(val)
## except:
## pass
## finally:
## robotServer.closeConnection()
## sys.exit(0)
I have the following code running and I would like to have the output of the script exported to a .txt file for later viewing. How could I go about doing this?
import socket, threading
def TCP_connect(ip, port_number, delay, output):
TCPsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
TCPsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
TCPsock.settimeout(delay)
try:
TCPsock.connect((ip, port_number))
output[port_number] = 'Listening'
except:
output[port_number] = ''
def scan_ports(host_ip, delay):
threads = [] # To run TCP_connect concurrently
output = {} # For printing purposes
# Spawning threads to scan ports
for i in range(10000):
t = threading.Thread(target=TCP_connect, args=(host_ip, i, delay, output))
threads.append(t)
# Starting threads
for i in range(10000):
threads[i].start()
# Locking the script until all threads complete
for i in range(10000):
threads[i].join()
# Printing listening ports from small to large
for i in range(10000):
if output[i] == 'Listening':
print(str(i) + ': ' + output[i])
def main():
host_ip = input("Enter host IP: ")
delay = int(input("How many seconds the socket is going to wait until timeout: "))
scan_ports(host_ip, delay)
if __name__ == "__main__":
main()
print ("Thank you for scanning")
Any help would be greatly appreciated.
with open("your_desired_txt_filename", "a") as myFile:
Then, at the part where you want to write to the file:
myFile.write(your_content) ## Indent this line with the suitable level of indentation (it will be at least one indentation level deeper than the `with` clause
I am trying to implement a server for handling many clients (from thenewboston python reverse shell tutorials). I have the exact same code but when i run the script it gets stuck at queue.join(). How to make it work? I am unable to figure it out.
Here is the code
import socket
import sys
import threading
from queue import Queue
NUMBER_OF_THREADS = 2
JOB_NUMBER = [1, 2]
queue = Queue()
all_connections = []
all_addresses = []
# thread 1
# create socket (allows two computers to connect)
def socket_create():
try:
global host # ip address of the server
global port # port is to identify the kind of data
global s
host = ''
port = 9999
s = socket.socket()
except socket.error as msg:
print("Socket creation error: " + str(msg))
return
# bind socket to port and wait for connection from client
def socket_bind():
try:
global host
global port
global s
print("Binding socket to port: " + str(port))
s.bind((host, port))
s.listen(5)
# 5 is the no. of conections that can be made before server starts rejecting other requests
except socket.error as msg:
print("Socket binding error: " + str(msg) + "\n" + "Retrying...")
socket_bind()
return
# accept connections from multiple clients and save to list
def accept_connections():
for c in all_connections:
c.close()
del all_connections[:]
del all_addresses[:]
while 1:
try:
conn, address = s.accept()
conn.setblocking(1)
all_connections.append(conn)
all_addresses.append(address)
print("\nConnection has been establish: " + address[0])
except:
print("Error accepting connections")
return
# thread 2
# custom command promt for sending commands remotely
def start_turtle():
while True:
cmd = input('turtle> ')
if cmd == 'list':
list_connections()
elif 'select' in cmd:
conn = get_target(cmd)
if conn is not None:
send_target_commands(conn)
else:
print("Command not recognized")
return
# listing all the connections with indexing in the custom promt
def list_connections():
results = ''
for i, conn in enumerate(all_connections):
try:
conn.send(str.encode(' '))
conn.recv(20480)
except:
del all_connections[i]
del all_addresses[i]
continue
results += str(i) + ' ' + str(all_addresses[i][0]) + ' ' + str(all_addresses[i][1]) + '\n'
print('-----Clients-----' + '\n' + results)
return
# select a target client
def get_target(cmd):
try:
target = cmd.replace('select ', '')
target = int(target)
conn = all_connections[target]
print("You are now connected to " + str(all_addresses[target][0]))
print(str(all_addresses[target][0]) + '> ', end="")
return conn
except:
print("Not a valid selection")
return None
return
# connect with remote target client
def send_target_commands(conn):
while True:
try:
cmd = input()
if len(str.encode(cmd)) > 0:
conn.send(str.encode(cmd))
client_response = str(conn.recv(20480), "utf-8")
print(client_response, end="")
if cmd == "quit":
break
except:
print("Connection was lost")
break
return
# create worker threads
def create_workers():
for _ in range(NUMBER_OF_THREADS):
t = threading.Thread(target=work)
t.daemon = True
t.start
return
# do the next job in the queue (one handles connections, other sends commands)
def work():
while True:
x = queue.get()
if x == 1:
socket_create()
socket_bind()
accept_connections()
if x == 2:
start_turtle()
queue.task_done()
return
# create jobs for later extracting them and assigning them to the threads
def create_jobs():
for x in JOB_NUMBER:
queue.put(x)
queue.join()
return
def main():
create_workers()
create_jobs()
if __name__ == '__main__':
main()
Since you are using infinite loops (while True) at start_turtle and (while 1) at accept_connections they are not returning.
Since they don't return the func work never calls queue.task_done(), so the queue stuck joining.
I'm afraid you need to do one of the following:
start both start_turtle and accept_connections in parallel processes or threads.
Be sure they should call the queue.task_done().
For instance, you may include the queue as parameter and call it before starting the infinite loops (second option).
def work():
while True:
x = queue.get()
if x == 1:
socket_create()
socket_bind()
accept_connections(queue) # call queue.task_done() there
if x == 2:
start_turtle(queue) # call queue.task_done() in start_turtle
return
def start_turtle(queue):
queue.task_done() # Join one item from the queue
while True:
cmd = input('turtle> ')
if cmd == 'list':
list_connections()
elif 'select' in cmd:
conn = get_target(cmd)
if conn is not None:
send_target_commands(conn)
else:
print("Command not recognized")
return
On the other hand, in your create_workers you don't call the start method of the thread so your workers didn't really start.
Perhaps this is a typo.
def create_workers():
for _ in range(NUMBER_OF_THREADS):
t = threading.Thread(target=work)
t.daemon = True
# t.start # Not starting the Thread
t.start() # You need to call the start method
return
Here's the code giving me the issue:
def connect():
s.listen(2)
print("Server listening")
conn,addr=s.accept()
print("Connected with " + str(addr) + '\n')
recv()
def recv():
while 1:
try:
print("Starting try statement")
data=conn.recv(1024)
if data == "":
print("No data")
recv()
else:
print("Data")
print(data.decode('UTF-8') + " -END")
recv()
except:
print("No connection")
connect()
conn.close()
When I execute the code, it'll connect to the client and be ready to receive a message at any point. However, once it's executed this is what appears.
Server listening
Connected with ('xx.xxx.xxx.xx', xxxxx)
Starting try statement
No connection
Server listening
IP censored. Does anyone have a fix for this?
EDIT: Typo
CLIENT CODE (From TKinter GUI)
s.connect((host,port))
self.chatlog['state'] = NORMAL
self.chatlog.insert(END, ("===CONNECTED TO SERVER\n"))
self.chatlog['state'] = DISABLED
self.chatlog.yview(END)
self.conn=True
print("Connected")
You are doing it wrong.
Ya 'now that local conn what you are creating in function connect is not accessible from function recv? That is a reason for not reciving anything.
My solution using that code, without using classes and threads but with select and sys module is:
import sys
import select
def connect()
s.listen(2)
print('Sever listening')
inputs = [s, sys.stdin]
running = 1
while running:
i_rdy = select.select(inputs,[],[],1)[0]
if s in i_rdy:
conn, addr = s.accept()
print ('Connected with ' + str(addr) + '\n')
recv(conn)
if sys.stdin in i_rdy:
junk = std.stdin.readline()
if junk.lstrip('\n') == 'exit':
running = 0
print('Closing server')
s.close()
def recv(conn):
while 1:
try:
print("Starting try statement")
data = conn.recv(1024)
if data == "":
print("No data")
else:
print("Data")
print(data.decode('UTF-8') + " -END")
except:
print("No connection")
#traceback
print(sys.exc_info)
break
try:
conn.close()
except:
pass
As you can see can "exit" when u type exit to console but only when there is no active connection...
That why you should consider rewrite this to classes, it would be a lot easier to stop, not "ugly" and it could handle multiple connections.
I'm trying to write a handler/controller for the Minecraft server. My problem is that I can't seem get writing and reading to work properly. When a client issues a command that uses the server class's method serverCom, the Minecraft server's text/log starts to come into the Python window/Python console and the connected client hangs. Also, it seems that after I use Popen, the Minecraft server doesn't really launch until I do write to the server (aka serverCom method). In case anyone is wondering, the Popen goes to a batch file that opens the .jar file. This is on Windows XP.
import subprocess
import os
import configobj
import socket
import threading
from time import sleep
config = configobj.ConfigObj("config.ini")
cHost = config["hostip"]
cPort = int(config["hostport"])
cBuffer = int(config["serverbuffer"])
cClients = int(config["numberofclients"])
cPassword = config["password"]
class server(object):
def __init__(self):
self.process = False
self.folder = "C:\\servers\\minecraft-danny"
self.max = configobj.ConfigObj("%s\\simpleserver.properties"%self.folder)["maxPlayers"]
def serverStart(self):
if not self.process:
self.process = subprocess.Popen("java -Xmx1024m -Xms1024m -jar minecraft_server.jar nogui", cBuffer, None, subprocess.PIPE, subprocess.PIPE, subprocess.STDOUT, cwd = self.folder)
return True
return False
def serverStop(self):
if self.process:
self.serverCom("stop")
self.process = False
return True
return False
def serverCom(self, text):
if self.process:
self.process.stdout.seek(2)
self.process.stdin.write("%s\n"%text)
self.process.stdin.flush()
self.process.stdout.flush()
return (str(self.process.stdout.readline()), True)
return ("", False)
def serverPlayers(self):
if self.process:
self.serverCom("list")
x = self.serverCom(" ")[0].split(":")[3].replace("\n","").replace(" ","")
if x == "":
x = 0
else:
x = len(x.split(","))
return (x, self.max)
return (0,self.max)
serv = server()
def client(cnct, adr):
global count
try:
dat = str(cnct.recv(cBuffer)).split(" ")
ans = False
if dat[0] == "start":
print "Client %s:%s started the MC Server....."%(adr[0], adr[1])
x = serv.serverStart()
sleep(1)
serv.serverCom(" ")
serv.serverCom(" ")
sleep(5)
if x:
ans = "Server is now online."
else:
ans = "Server is already online."
elif dat[0] == "stop":
print "Client %s:%s stopped the MC Server....."%(adr[0], adr[1])
x = serv.serverStop()
sleep(6)
if x:
ans = "Server is now offline."
else:
ans = "Server is already offline."
elif dat[0] == "commun":
print "Client %s:%s executed a command on the MC Server....."%(adr[0], adr[1])
serv.serverCom(" ".join(dat[1:]))
x = serv.serverCom(" ")
if x[1]:
ans = x[0]
else:
ans = "No return text, server is offline or not responding."
elif dat[0] == "players":
print "Client %s:%s recieved the player count from the MC Server....."%(adr[0], adr[1])
pc = serv.serverPlayers()
ans = "%s/%s"%(pc[0],pc[1])
elif dat[0] == "help":
print "Client %s:%s recieved the help list....."%(adr[0], adr[1])
ans = "__________\nstart - Starts the server.\nstop - Stops the server.\ncommun <command> - Writes to server's console.\nplayers - Returns player count.\nhelp - Shows this help.\nclose - Closes client connections.\n__________"
elif dat[0] == "close":
pass
else:
ans = "Command '%s' is not valid."%dat[0]
if ans:
cnct.send("PASS")
cnct.send("%s\n"%ans)
threading.Thread(target = client, args = (cnct, adr,)).start()
else:
cnct.send("DICN")
cnct.send("Connection to server closed.\n")
cnct.close()
print "Client %s:%s disconnected....."%(adr[0], adr[1])
if count:
count -= 1
except:
cnct.close()
print "Client %s:%s disconnected..... "%(adr[0], adr[1])
if count:
count -= 1
print "-MC Server Control Server v0.0.1 BETA-"
print "Starting up server....."
print "Connecting to socket....."
count = 0
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.bind((cHost, cPort))
sck.listen(5)
print "Connected and listening on %s:%s....."%(cHost, cPort)
print "Setting up client listener, allowing %s clients to connect at a time....."%cClients
while True:
for x in range(cClients):
(cnct, adr) = sck.accept()
print "Client %s:%s connected....."%(adr[0], adr[1])
cnct.send("Welcome to MineCraft Server Control.\n\nPlease enter server control password.\n")
ps = str(cnct.recv(cBuffer))
if count < cClients:
if ps == cPassword:
cnct.send("CRRT")
cnct.send("%s was correct.\nIf you need help type 'help'."%ps)
count += 1
threading.Thread(target = client, args = (cnct, adr,)).start()
else:
cnct.send("WRNG")
cnct.send("%s wasn't the correct password, please try again."%ps)
cnct.close()
print "Client %s:%s rejected....."%(adr[0], adr[1])
else:
cnct.send("WRNG")
cnct.send("Too many clients connected to MineCraft Server Control")
cnct.close()
print "Client %s:%s rejected....."%(adr[0], adr[1])
sck.close()
I have no idea how a Minecraft server works, but there are a number of problems with your code:
You are redirecting stderr to stdout from the created Java process, then expecting a line response from the server. This could be the reason that the Minecraft server is not starting, since it would block on a stderr write (depending on how Windows XP handles it). Additionally, any stderr write (e.g. log write) will destroy any structured responses you may be waiting for.
You are reading with sock.recv(N) and then assuming that you get the whole chunk (e.g. password). This is not how TCP works, you may very well get just one character back (especially true if the user types the password interactively e.g. in a Telnet prompt).
You are flushing the stdout of the subprocess, which is your input stream. You probably want to flush the stdin of the subprocess. Flushing an input stream makes no sense, it is the output stream that determines when to flush.