How to write/read serial port with multithreading using pyserial - python

I'm currently running into a problem with trying to write to a serial device using pySerial. I want to be able to continuously update my terminal by reading the port and handle serial device writing on a seperate thread, meanwhile also be able to send a command via user input on the main thread. Everything runs as expected, except for that when I send one of the commands (cmdA or cmdB), the serial's output that I'm reading does not change (this is expected behaviour as the commands being sent alter the state of the device, which in turn changes the device's output that the serial port is reading). With all that said, it seems that the device is not receiving the command I am sending, even though the code continues to run with no exception and all functions seem to be executing as written.
Here is my current code:
A SerialMonitor class that can read the serial port and print out a specific amount of bytes once finding a set of "syncbytes"
# SerialMonitorTool.py
import threading
import time
import serial
class SerialMonitor(threading.Thread):
SYNC_BYTES = b'\x90\xeb'
def __init__(self, device='/dev/ttyUSB0', baudrate=115200, timeout=5):
print("Initializing Serial Monitor")
self._running = False
self._name = 'SerialMonitorThread-{}'.format(device)
self._device = serial.Serial(device, baudrate=baudrate, timeout=timeout)
self._write_lock = threading.Lock()
super().__init__(name=self._name)
def write(self, user_input, encode=False, terminator=None):
print("Locking for CMD Write...")
self._write_lock.acquire()
tx = user_input + terminator if terminator else user_input
print(f"Writing CMD to device: {tx}")
self._device.write(tx.encode() if encode else tx)
print("CMD Written...")
self._write_lock.release()
print("CMD Write Lock Released...")
def stop(self):
self._running = False
print('stop thread: ' + threading.current_thread().getName())
self.join()
def run(self):
print('starting thread: ' + threading.current_thread().getName())
self._running = True
try:
while self._running:
self._device.reset_input_buffer()
self._device.read_until(self.SYNC_BYTES)
ser_bytes = self._device.read(35)
print(f'\r{ser_bytes}', end='', flush=True)
time.sleep(0.25)
finally:
self._device.close()
and the main thread
# SerialMain.py
from SerialMonitorTool import *
cmdA = b'\x90\xeb\x01'
cmdB = b'\x90\xeb\x02'
monitor: SerialMonitor()
def print_help():
print('Usage: cmd [ a | b ]')
def send_cmd(cmd):
monitor.write(cmd)
def main():
monitor.start()
while True:
try:
user_input = input()
if user_input == '?' or user_input == 'h' or user_input == 'help':
print_help()
elif user_input == 'q' or user_input == 'quit':
break
elif user_input.startswith('cmd '):
cmd_type = user_input[len('cmd '):].split(' ')
if cmd_type[0] == 'a':
send_cmd(cmdA)
elif cmd_type[0] == 'b':
send_cmd(cmdB)
except Exception as e:
print(e)
monitor.stop()
def process_args():
# process arguments
import argparse
parser = argparse.ArgumentParser(description='Serial Test Tool')
parser.add_argument(
'-D', '--device',
help='Use the specified serial device.',
default='/dev/ttyUSB0',
type=str
)
global monitor
monitor = SerialMonitor()
if __name__ == "__main__":
process_args()
main()

It looks like there is issue in your write method, try to comment all the lock related code in write method or put lock syntax in below sequence.
def write(self, user_input, encode=False, terminator=None):
tx = user_input + terminator if terminator else user_input
print(f"Writing CMD to device: {tx}")
self._device.write(tx.encode() if encode else tx)
print("CMD Written...")
print("Locking for CMD Write...")
self._write_lock.acquire()
self._write_lock.release()
print("CMD Write Lock Released...")

Related

Python / PySerial / Arduino Reading serial data and later writing this exact serial data to the txt file

I am making a new post regarding this case because I was misunderstood in the first one...
I have a code that reads the serial data from the Arduino and when some specific digits are pressed on the keyboard it writes these digits to the Arduino. This exact code works perfectly when I run it, it reads the serial data and I am able to write data to the Arduino. I use threading and PySerial library to achieve this.
from pynput import keyboard
import threading
import serial
import sys
ser = None
class SerialReaderThread(threading.Thread):
def run(self):
global ser
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
while True:
print(ser.readline().decode('utf-8'))
class KeyboardThread(threading.Thread):
def run(self):
def on_press(key):
try:
format(key.char)
if key.char == "1":
ser.write(b'1\r\n') #serial write - 1
elif key.char == "2":
ser.write(b'2\r\n') #serial write - 2
elif key.char == "3":
ser.write(b'3\r\n') #serial write - 3
elif key.char == "4":
ser.write(b'4\r\n') #serial write - 4
elif key.char == "5":
ser.write(b'5\r\n') #serial write - 5
elif key.char == "6":
ser.write(b'6\r\n') #serial write - 6
elif key.char == "0":
ser.write(b'0\r\n') #serial write - 0
except AttributeError:
format(key)
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
listener = keyboard.Listener(on_press=on_press)
listener.start()
serial_thread = SerialReaderThread()
keyboard_thread = KeyboardThread()
serial_thread.start()
keyboard_thread.start()
serial_thread.join()
keyboard_thread.join()
After this I got an idea that I could also write this serial data exactly what I was printing to the .txt file on windows. So I made a new thread called FileWriting and decided to just write ser.readline().decode('utf-8') to it, however it doesn't work anymore... This is the newly modified code which I wrote to write to the .txt file.
from pynput import keyboard
import threading
import serial
import sys
import io
ser = None
class SerialReaderThread(threading.Thread):
def run(self):
global ser
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
while True:
print(ser.readline().decode('utf-8'))
class FileWriting(threading.Thread):
def run(self):
while True:
with io.open("output.txt", "a", encoding="utf-8") as f:
f.write(ser.readline().decode('utf-8'))
class KeyboardThread(threading.Thread):
def run(self):
def on_press(key):
try:
format(key.char)
if key.char == "1":
ser.write(b'1\r\n') #serial write - 1
elif key.char == "2":
ser.write(b'2\r\n') #serial write - 2
elif key.char == "3":
ser.write(b'3\r\n') #serial write - 3
elif key.char == "4":
ser.write(b'4\r\n') #serial write - 4
elif key.char == "5":
ser.write(b'5\r\n') #serial write - 5
elif key.char == "6":
ser.write(b'6\r\n') #serial write - 6
elif key.char == "0":
ser.write(b'0\r\n') #serial write - 0
except AttributeError:
format(key)
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
listener = keyboard.Listener(on_press=on_press)
listener.start()
serial_thread = SerialReaderThread()
keyboard_thread = KeyboardThread()
file_thread = FileWriting()
serial_thread.start()
keyboard_thread.start()
file_thread.start()
serial_thread.join()
keyboard_thread.join()
file_thread.join()
As it's clear I only added a new thread called file_thread, now as I run the code printing of the serial data works fine as well as the writing data to the Arduino, however, the code doesn't write anything to the .txt file and gives me an error:
Exception in thread Thread-3:
Traceback (most recent call last):
File "C:\Python\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Users\ultra\Desktop\work\menucode.py", line 32, in run
f.write(ser.readline().decode('utf-8'))
AttributeError: 'NoneType' object has no attribute 'readline'
If anybody had similar problems with Arduino while reading the serial data and writing to the text file, or if anybody knows how to fix this please let me know I am quite desperate at this point and everything is appreciated.
At the top of your file, you declare ser = None. The error message you get indicate that the ser object has not yet been set to a Serial object before the FileWriting thread tries to access it.
A quick way to fix this issue is by doing
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
before you start any of the threads.
However, that would probably make the program behave strangely, as you have two competing ser.readline() calls in different threads. This would probably result in roughly half of the Arduino's output data being captured by each of the threads (depending on how pyserial handles multiple requests for the same resource). To avoid this issue, I would recommend letting a single thread interface with the ser object, and having that thread pass data to other threads using a queue.
A simple example of how this data exchange could go:
import queue
import serial
q = queue.Queue()
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)
class SerialReaderThread(threading.Thread):
def run(self):
while True:
# Read output from ser
output = ser.readline().decode('utf-8')
print(output)
# Add output to queue
q.put(output)
class FileWriting(threading.Thread):
def run(self):
while True:
output = q.get() # This will wait until an item is available in the queue
with open("output.txt", "a+") as f:
f.write(output)
f.write("\n") # If you want outputs separated by newlines

I want to run and kill a thread on a button press

I have a program that is supposed to send a few data points over a serial connection to an arduino which will control some motors to move. I can send the control signals individually as well as by txt file which will run repeatedly until the file is complete. While running a txt file, I want to be able to exit the loop like a pause or stop button. I think the best way to do that is via a thread that I can close. I have never done any threading before and my rudimentary attempts have not worked. Here is the function that sends the file data.
def send_file():
# Global vars
global moto1pos
global motor2pos
# Set Ready value
global isready
# Get File location
program_file_name = file_list.get('active')
file_path = "/home/evan/Documents/bar_text_files/"
program_file = Path(file_path + program_file_name)
file = open(program_file)
pos1 = []
pos2 = []
speed1 = []
speed2 = []
accel1 = []
accel2 = []
for each in file:
vals = each.split()
pos1.append(int(vals[0]))
pos2.append(int(vals[1]))
speed1.append(int(vals[2]))
speed2.append(int(vals[3]))
accel1.append(int(vals[4]))
accel2.append(int(vals[5]))
# Send file values
try:
while isready == 1:
for i in range(len(pos1)):
print("Step: " + str(i+1))
data = struct.pack("!llhhhh", pos1[i], pos2[i], speed1[i], speed2[i], accel1[i], accel2[i])
ser.write(data)
try:
pos1time = abs(pos1[i]/speed1[i])
except:
pos1time = 0
try:
pos2time = abs(pos2[i]/speed2[i])
except:
pos2time = 0
time_array = (pos1time, pos2time)
time.sleep(max(time_array))
motor1pos = ser.readline()
motor2pos = ser.readline()
if i < (len(pos1)-1):
isready = ord(ser.read(1))
else:
isready = 0
except:
print("Error: data not sent. Check serial port is open")
Here is the threading command which I want the sendfile command to work from.
def thread():
try:
global isready
isready = 1
t = threading.Thread(name='sending_data', target=command)
t.start()
except:
print("Threading Error: you don't know what you are doing")
And here is the stop function I want the thread to be killed by:
def stop():
try:
global isready
isready = 0
t.kill()
except:
print("Error: thread wasn't killed")
I know you aren't supposed to kill a thread but the data isn't very important. Whats more important is to stop the motors before something breaks.
The button in tkinter is:
run_file_butt = tk.Button(master = file_frame, text = "Run File", command = thread)
When I click the button, the program runs but the stop function does nothing to stop the motion.
Question: run and kill a thread on a button press
There is no such a thing called .kill(....
Start making your def send_file(... a Thread object which is waiting your commands.
Note: As it stands, your inner while isready == 1: will not stop by using m.set_state('stop').
It's mandatory to start the Thread object inside:
if __name__ == '__main__':
m = MotorControl()
import threading, time
class MotorControl(threading.Thread):
def __init__(self):
super().__init__()
self.state = {'is_alive'}
self.start()
def set_state(self, state):
if state == 'stop':
state = 'idle'
self.state.add(state)
def terminate(self):
self.state = {}
# main function in a Thread object
def run(self):
# Here goes your initalisation
# ...
while 'is_alive' in self.state:
if 'start' in self.state:
isready = 1
while isready == 1:
# Here goes your activity
# Simulate activity
print('running')
time.sleep(2)
isready = 0
self.state = self.state - {'start'}
self.state.add('idle')
elif 'idle' in self.state:
print('idle')
time.sleep(1)
if __name__ == '__main__':
m = MotorControl()
time.sleep(2)
m.set_state('start')
time.sleep(3)
m.set_state('stop')
time.sleep(3)
m.set_state('start')
time.sleep(4)
m.terminate()
print('EXIT __main__')
Your tk.Button should look like:
tk.Button(text = "Run File", command = lambda:m.set_state('start'))
tk.Button(text = "Stop File", command = lambda:m.set_state('stop'))
tk.Button(text = "Terminate", command = m.terminate)
The answer I have gone with is simple due to my simple understanding of threading and unique circumstances with which I am using the threading. Instead of terminating the thread in a way I was hoping, I added another conditional statement to the sending line of the send_file function.
while isready == 1:
for i in range(len(pos1)):
if motorstop == False:
print("Step: " + str(i+1))
#data = struct.pack('!llllhhhhhhhh', pos1[i], pos2[i], pos3[i], pos4[i], speed1[i], speed2[i], speed3[i], speed[4], accel1[i], accel2[i], accel3[i], accel4[i])
data = struct.pack("!llhhhh", pos1[i], pos2[i], speed1[i], speed2[i], accel1[i], accel2[i])
ser.write(data)
else:
isready = 0
break
and I have updated my stop() func to the following:
def stop():
try:
global motorstop
global t
motorstop = True
t.join()
except:
print("Error: thread wasn't killed")
I'm not exactly sure how it works but it is much simpler than what was mentioned by #stovefl.
With this code, since the function is mostly just sleeping, it can run but it won't send any new information and then will .join() after the next iteration.

Python script stuck at queue.join()

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

python thread waits for input before it prints

I'm writing a socket communication program, I have a main thread, and another thread trying to sock.recv()
when it does recieve bytes, it works as it needs, it goes to the right function, which at the end prints, and then the thread listens again to bytes (as wanted).
the problem is that the program won't print until I press enter...
if it matters i'm getting input at the same time in the main thread but it shouldn't matter.
note - the bytes are sent like this:
int (4 bytes) - msg type (string to print is 2)
int (4 bytes) - length of text to print
string ( bytes) - actual text
full code:
import socket
import time
import struct
import threading
import sys
PORT = 54321
def try_to_connect(ip):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
socket.IPPROTO_TCP)
sock.settimeout(1)
try:
sock.connect((ip, PORT))
return sock
except:
return False
def text_parse(text, msg_id):
byte_text = bytes(text, "utf-8")
return struct.pack("II%ds" % len(byte_text), msg_id, len(byte_text), byte_text)
def main(sock):
global file_name
print("connected succefuly. to run a command, write $<command> (no space)\nto request a file, enter file path.\nto exit this program enter exit.")
inputed_text = ''
while True:
inputed_text = input()
if inputed_text == '':
pass
elif inputed_text == "exit":
return
elif inputed_text[0] == "$":
sock.send(text_parse(inputed_text[1:], 0))
else:
file_name = inputed_text
sock.send(text_parse(inputed_text, 1))
def print_string(message, msg_len):
text = struct.unpack("%ds" % msg_len, message)[0].decode("utf-8")
sys.stdout.write(text)
sys.stdout.flush()
def copy_file(message):
global file_name
final_file = open(file_name, "wb")
final_file.write(message)
final_file.close()
def recieve_loop(sock):
while True:
try:
header = sock.recv(8)
if not header: break
msg_type = struct.unpack("I", header[:4])[0]
msg_len = struct.unpack("I", header[4:8])[0]
print(msg_type)
print(msg_len)
message = sock.recv(msg_len)
if msg_type == 2:
print_string(message, msg_len)
elif msg_type == 3:
copy_file(message)
except socket.timeout:
pass
if __name__ == "__main__":
print("welcome to remote desktop program.\nto connect to your computer, enter it's ip.\nto exit enter exit")
text_input = "b,kjhkf"
while True:
text_input = input()
if text_input == "exit":
exit()
else:
sock = try_to_connect(text_input)
if sock:
socket_recieve_thread = threading.Thread(target = recieve_loop, args = [sock])
socket_recieve_thread.start()
main(sock)
socket_recieve_thread.join()
else:
print("the computer is not online")

Python can't communicate with subprocess of a Minecraft server

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.

Categories