Thanks to #user5402 for the previous solution.
I am trying to handle multiple messages that are queued up. Here is the code:
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)
In the client function I want to handle multiple messages, that have knock on affects.
def client():
q = Queue()
r = Process(target = receive, args=(q,))
r.start()
print "client loop started"
while True:
m = q.get()
print "got:", m
while m == "start":
print "started"
z = q.get()
if z == "stop":
return
print "loop ended"
r.terminate()
So when start is sent, it then goes into a while loop that is infinitely printing "started", and waiting for the stop message to come through. The above client code does not work.
Here is the code to start the function:
if __name__ == '__main__':
args = sys.argv
if len(args) > 1:
send(args[1])
else:
client()
You can write the client loop like this:
print "client loop started"
while True:
m = q.get()
print "waiting for start, got:", m
if m == "start":
while True:
try:
m = q.get(False)
except:
m = None
print "waiting for stop, got:", m
if m == "stop":
break
Based on your comments, this would be a better approach:
import sys
import socket
import Queue as Q
import time
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 doit():
# ... what the processing thread will do ...
while True:
print "sleeping..."
time.sleep(3)
def client():
q = Queue()
r = Process(target = receive, args=(q,))
r.start()
print "client loop started"
t = None # the processing thread
while True:
m = q.get()
if m == "start":
if t:
print "processing thread already started"
else:
t = Process(target = doit)
t.start()
print "processing thread started"
elif m == "stop":
if t:
t.terminate()
t = None
print "processing thread stopped"
else:
print "processing thread not running"
elif m == "quit":
print "shutting down"
if t:
t.terminate()
t = None # play it safe
break
else:
print "huh?"
r.terminate()
if __name__ == '__main__':
args = sys.argv
if len(args) > 1:
send(args[1])
else:
client()
Related
I have a program(python 3.9.10) that has a read queue and a write queue. One thread reads and once read, sends to the write queue and another thread writes.
All works fine unless there is an error. If there is, the threads do not stop.
In the following code I am simulating an error being detected in the read thread and trying to stop the threads from reading/writing so the program exits however the program/threads stay active and the program never finishes. If I remove the error simulation code, the threads stop and the program finishes.
I wish to handle the errors WITHIN the threads and if need be, stop the threads/program without throwing an error up
What am I doing wrong? Thanks
Here is a working example of my issue:
import pandas as pd
import datetime
import traceback
from queue import Queue
from threading import Thread
import time
dlQueue = Queue()
writeQueue = Queue()
dlQDone = False
errorStop = False
def log(text):
text = datetime.datetime.now().strftime("%Y/%m/%d, %H:%M:%S ") + text
print(text)
def errorBreak():
global dlQueue
global writeQueue
global errorStop
global dlQDone
dlQueue = Queue()
writeQueue = Queue()
errorStop = True
dlQDone = True
def downloadTable(t, q):
global dlQDone
global errorStop
while True:
if errorStop:
return
nextQ = q.get()
log("READING: " + nextQ)
writeQueue.put("Writing " + nextQ)
log("DONE READING: " + nextQ)
####sumulating an error and need to exit threads###
if nextQ == "Read 7":
log("Breaking Read")
errorBreak()
return
###################################################
q.task_done()
if q.qsize() == 0:
log("Download QUEUE finished")
dlQDone = True
return
def writeTable(t, q):
global errorStop
global dlQDone
while True:
if errorStop:
log("Error Stop return")
return
nextQ = q.get()
log("WRITING: " + nextQ)
log("DONE WRITING: " + nextQ)
q.task_done()
if dlQDone:
if q.qsize() == 0:
log("Writing QUEUE finished")
return
try:
log("PROCESS STARTING!!")
for i in range(10):
dlQueue.put("Read " + str(i))
startTime = time.time()
log("Starting threaded pull....")
dlWorker = Thread(
target=downloadTable,
args=(
"DL",
dlQueue,
),
)
dlWorker.start()
writeWorker = Thread(
target=writeTable,
args=(
"Write",
writeQueue,
),
)
writeWorker.start()
dlQueue.join()
writeQueue.join()
log(f"Finished thread in {str(time.time() - startTime)} seconds") # CANNOT GET HERE
log("Threads: " + str(dlWorker.is_alive()) + str(writeWorker.is_alive()))
except Exception as error:
log(error)
log(traceback.format_exc())
If I understood you correctly, you want to stop both threads in case there's some error that warrants it; you can do that with a threading.Event, and changing your queue reads to have a timeout.
import datetime
import time
import queue
import threading
dlQueue = queue.Queue()
writeQueue = queue.Queue()
stop_event = threading.Event()
def log(text):
text = datetime.datetime.now().strftime("%Y/%m/%d, %H:%M:%S ") + text
print(text)
def downloadTable(t: str, q: queue.Queue):
while not stop_event.is_set():
try:
nextQ = q.get(timeout=1)
except queue.Empty:
continue
log("READING: " + nextQ)
writeQueue.put("Writing " + nextQ)
log("DONE READING: " + nextQ)
if nextQ == "7":
log("Breaking Read")
stop_event.set()
break
q.task_done()
log("Download thread exiting")
def writeTable(t, q):
while not stop_event.is_set():
try:
nextQ = q.get(timeout=1)
except queue.Empty:
continue
log("WRITING: " + nextQ)
log("DONE WRITING: " + nextQ)
q.task_done()
log("Write thread exiting")
def main():
log("PROCESS STARTING!!")
for i in range(10):
dlQueue.put(f"{i}")
log("Starting threaded pull....")
dlWorker = threading.Thread(
target=downloadTable,
args=(
"DL",
dlQueue,
),
)
dlWorker.start()
writeWorker = threading.Thread(
target=writeTable,
args=(
"Write",
writeQueue,
),
)
writeWorker.start()
dlWorker.join()
writeWorker.join()
if __name__ == "__main__":
main()
I am trying to write a small client-server application in Python. The server must generate a random number and send it to the client. The client checks if the number it received is prime. In that case it will send to the server the message "YES". If the number is not prime it will send a "NO" message to the server. Then the server checks the reply and if it is "YES"/"NO", it will send the client the message "CORRECT"/"WRONG" and the client will display it. The app works fine for one client, but when multiple clients are accessing the app at the same time I get errors like this: "invalid literal for int() with base 10: 'Wrong'" and sometimes I get "An existing connection was forcibly closed by the remote host". Can you please tell me what am I doing wrong?
server.py:
import socket
import random
import threading
class ClientHandler(threading.Thread):
def __init__(self, client_sock, client_addr):
self.client_sock = client_sock
self.client_addr = client_addr
super(ClientHandler, self).__init__()
def run(self):
n = random.randint(0, 9)
trimite = str(n)
self.client_sock.send(bytes(trimite, "utf-8"))
received = None
while received == None:
received = client_sock.recv(100)
received = received.decode("utf-8")
if received == "YES":
client_sock.send(b"Correct")
else:
client_sock.send(b"Wrong")
self.client_sock.close()
if __name__ == '__main__':
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("0.0.0.0", 9999))
sock.listen(10)
while True:
client_sock, client_addr = sock.accept()
print(f"Connected {client_addr[0]} : {client_addr[1]}")
worker_thread = ClientHandler(client_sock, client_addr)
worker_thread.start()
client.py:
import socket
import threading
def check_prime(n):
n = int(n)
if n == 1 or n == 0:
return False
if n == 2:
return True
for i in range(2, n // 2):
if n % i == 0:
return False
return True
class RunMultiple(threading.Thread):
def __init__(self, sock):
self.sock = sock
super(RunMultiple, self).__init__()
def run(self):
recieved = self.sock.recv(100)
if check_prime(recieved.decode("utf-8")) == True:
self.sock.send(b"YES")
else:
self.sock.send(b"NO")
second_recieved = self.sock.recv(100)
print(second_recieved.decode("utf 8"))
if __name__ == "__main__":
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("127.0.0.1", 9999))
i = 0
while i != 3:
worker_thread = RunMultiple(sock)
worker_thread.start()
i += 1
Open a new connection for each client:
if __name__ == "__main__":
for i in range(3):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("127.0.0.1", 9999))
worker_thread = RunMultiple(sock)
worker_thread.start()
And make sure to use self.client_sock not client_sock in the server. Without it, it was referencing the global variable defined in the if __name__ section of the code which is the last socket opened.
received = None
while received == None:
received = self.client_sock.recv(100) # was missing self here
received = received.decode("utf-8")
if received == "YES":
self.client_sock.send(b"Correct") # and here
else:
self.client_sock.send(b"Wrong") # and here
self.client_sock.close()
I am currently trying to make a Python program where two computers connected to different servers can send messages to each other.
Below is my code:
Server.py:
import sys
import socket
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 11111))
s.listen(1)
while True:
(conn, addr) = s.accept()
while True:
received = conn.recv(1024)
if received == '':
break
else:
print(received.decode())
send_msg = input().replace('b', '').encode()
if send_msg == ' ':
break
else:
conn.sendall(send_msg)
print("sent")
if __name__ == '__main__':
main()
Client.py:
import sys
import socket
import select
def main():
if len(sys.argv) is not 3:
print("usage: %s [ip adress][port] " % sys.argv[0] )
return(-1)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((sys.argv[1], int(sys.argv[2])))
while True:
s_msg = input().replace('b', '').encode('utf-8')
if s_msg == '':
break
else:
s.sendall(s_msg)
r_msg = s.recv(1024)
if r_msg == '':
break
else:
print(r_msg.decode())
if __name__ == '__main__':
main()
When I executed the code by sending a message from server.py, the message was not sent to the client until I try to send a message from the client to the server. Here is the example of the result:
Does anyone know what's wrong with my code?
Please let me know if any extra information is needed. Thank you in advance.
I was able to implement the simple P2P chat program using the code below:
server.py
import sys
import socket
import threading
#TODO: exit program when client ends the connection
def connect(conn):
while True:
received = conn.recv(1024)
if received ==' ':
pass
else:
print(received.decode())
def sendMsg(conn):
while True:
send_msg = input().replace('b', '').encode()
if send_msg == ' ':
pass
else:
conn.sendall(send_msg)
if __name__ == '__main__':
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 11111))
s.listen()
(conn, addr) = s.accept()
thread1 = threading.Thread(target = connect, args = ([conn]))
thread2 = threading.Thread(target = sendMsg, args = ([conn]))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
client.py
import sys
import socket
import threading
#TODO:end connection with 'exit'
def connect(s):
while True:
r_msg = s.recv(1024)
if not r_msg:
break
if r_msg == '':
pass
else:
print(r_msg.decode())
def receive(s):
while True:
s_msg = input().replace('b', '').encode('utf-8')
if s_msg == '':
pass
if s_msg.decode() == 'exit':
print("wan exit")
break
else:
s.sendall(s_msg)
if __name__ == '__main__':
if len(sys.argv) is not 3:
print("usage: %s [ip adress][port] " % sys.argv[0] )
sys.exit(0)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect((sys.argv[1], int(sys.argv[2])))
thread1 = threading.Thread(target = connect, args = ([s]))
thread2 = threading.Thread(target = receive, args = ([s]))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
In your code, input() is a blocking function, meaning the execution stop until you press Enter.
So you need to send a message to execute the receive part.
To deal with is issue, you can use non-blocking input functions as mentioned in this question.
Or maybe using multi-threaded code: one thread read the use input and send, the other thread receive and print.
Edit:
The server can't send messages if he receive nothing due to this line:
received = conn.recv(1024)
if the client is still connected and send nothing, the server will wait on this line. So you need to receive one message on server side to access the send part.
You can try to use non-blocking sockets to prevent this behavior.
I'm running windows 10, python 2.7 using pycharm
I'm doing as an exercise a socket chat room, and I've stumbled on a certain problem:
While running the client and server socket from multiple cmd windows,
When I exit one cmd window abruptly, the server is supposed to forward a message to the remaining client - informing them that a client left (including the client's nick)
For some reason it proves to be a problem, the server seems to retain that client in the client list, raising an error as if I sent him that message (which obviously is problematic, because he is no longer there).
When I tried to fix that - changing the loop to not send the message to that specific client (by saving his socket object) -it doesn't send any message.
As if it doesn't recognize the other clients.
My code:
Server:
import socket
import select
import datetime
server_socket=socket.socket()
server_socket.bind(('127.0.0.1',23))
server_socket.listen(5)
open_client_sockets = []
messages_to_send = []
chat_clients={}
def send_waiting_messages(wlist):
for message in messages_to_send:
(sender,msg)=message
if(msg=='\r'):
continue
elif(msg=='quit'):
pass
else:
nick_len=int(msg[:2])
nick=msg[2:2+nick_len]
chat=msg[2+nick_len:]
chat_clients[sender]=nick
for client in wlist:
if(msg=='quit'):
client.send(('{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,sender)))
else:
if(client is sender):
client.send('NL')
else:
client.send('{:02d}:{:02d} {}: {}'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,nick,chat))
messages_to_send.remove(message)
while True:
rlist,wlist,xlist=select.select([server_socket] + open_client_sockets,open_client_sockets,[])
for current_socket in rlist:
print wlist
if(current_socket is server_socket):
(new_socket,address)=server_socket.accept()
open_client_sockets.append(new_socket)
chat_clients[new_socket]=''
else:
try:
msg=current_socket.recv(1024)
except socket.error as e:
if e.errno==10054:
msg=''
else:
raise
if(msg=='' or msg=='quit'):
if(msg=='quit'):
messages_to_send.append((chat_clients[current_socket], 'quit'))
current_socket.send('quit')
open_client_sockets.remove(current_socket)
del chat_clients[current_socket]
else:
print '{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,
datetime.datetime.now().minute, chat_clients[current_socket])
messages_to_send.append((current_socket, 'quit'))
else:
print msg
messages_to_send.append((current_socket,msg))
send_waiting_messages(wlist)
Client:
import socket
import select
import datetime
server_socket=socket.socket()
server_socket.bind(('127.0.0.1',23))
server_socket.listen(5)
open_client_sockets = []
messages_to_send = []
chat_clients={}
def send_waiting_messages(wlist):
for message in messages_to_send:
(sender,msg)=message
if(msg=='\r'):
continue
elif(msg=='quit'):
pass
else:
nick_len=int(msg[:2])
nick=msg[2:2+nick_len]
chat=msg[2+nick_len:]
chat_clients[sender]=nick
for client in wlist:
if(msg=='quit'):
client.send(('{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,sender)))
else:
if(client is sender):
client.send('NL')
else:
client.send('{:02d}:{:02d} {}: {}'.format(datetime.datetime.now().hour,datetime.datetime.now().minute,nick,chat))
messages_to_send.remove(message)
while True:
rlist,wlist,xlist=select.select([server_socket] + open_client_sockets,open_client_sockets,[])
for current_socket in rlist:
print wlist
if(current_socket is server_socket):
(new_socket,address)=server_socket.accept()
open_client_sockets.append(new_socket)
chat_clients[new_socket]=''
else:
try:
msg=current_socket.recv(1024)
except socket.error as e:
if e.errno==10054:
msg=''
else:
raise
if(msg=='' or msg=='quit'):
if(msg=='quit'):
messages_to_send.append((chat_clients[current_socket], 'quit'))
current_socket.send('quit')
open_client_sockets.remove(current_socket)
del chat_clients[current_socket]
else:
print '{:02d}:{:02d} {} has left the chat!'.format(datetime.datetime.now().hour,
datetime.datetime.now().minute, chat_clients[current_socket])
messages_to_send.append((current_socket, 'quit'))
else:
print msg
messages_to_send.append((current_socket,msg))
send_waiting_messages(wlist)
Help would be much appreciated!
I have also been trying trying to make a chat room and I have been successful. You might want to look at my code to find the solution.
Server
import threading
from queue import Queue
import socket
host = ''
port = 5000
client_list = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(1000)
def conn():
while True:
(host, port) = s.accept()
f = len(client_list)
client_list.append(host)
print(client_list)
p1 = threading.Thread(target=clientam, args=str(f))
p2 = threading.Thread(target=threader)
p2.start()
p1.start()
p1.join()
p2.join()
def clientam(client):
size = 3000
client = int(client)
c = client_list[client]
print(c)
c.send("Welcome to the chatroom".encode())
while True:
try:
data = c.recv(size).decode()
if data == "exit":
for l in client_list:
if l == c:
pass
else:
l.send("The other person has left the chatroom".encode())
client_list[client] = ''
print(client_list)
c.close()
break
else:
for l in client_list:
if l == c:
pass
else:
l.send(data.encode())
except Exception:
for l in client_list:
if l == c:
continue
else:
try:
l.send("The other person has left the chatroom".encode())
except Exception:
pass
break
try:
c.close()
except Exception:
break
def threader():
t = threading.Thread(target=conn)
t.start()
t.join()
threader()
client
import socket
import threading
import time
import pickle
host = '127.0.0.1'
port = 5000
s = socket.socket()
d = 0
print_lock = threading.Lock()
def conn():
global d
global s
try:
if d == 1:
s = socket.socket()
s.connect((host, port))
d = 0
elif d == 0:
s.connect((host, port))
except Exception:
conn()
def reciever():
global d
global g
g = False
li = [128, 3, 88, 0, 113, 46]
size = 3000
while True:
try:
data = s.recv(size).decode()
data = str(data)
with open('Data.txt', 'a') as f:
f.write(data)
if str(data) == 'The other person has left the chatroom':
with print_lock:
print(data)
elif str(data) == "Welcome to the chatroom":
g = True
with print_lock:
print(str(data))
else:
try:
int(data)
continue
except Exception:
with print_lock:
print("Other Person:> " + str(data))
except Exception as e:
with print_lock:
print("You have been disconnected")
d = 1
s.close()
with print_lock:
print('Trying to connect to server')
conn()
def sender():
global d
global g
while True:
if g == True:
while True:
with print_lock:
i = input('You:> ')
if i == 'exit':
try:
s.send(i.encode())
with print_lock:
print("You have been disconnected")
d = 1
except Exception:
with print_lock:
print('You have been disconnected')
d = 1
elif i == "connect":
if d == 0:
with print_lock:
print("Server already connected")
elif d == 1:
with print_lock:
print('Server connecting')
conn()
else:
try:
if d == 0:
s.send(i.encode())
elif d == 1:
with print_lock:
print('Server is disconnected')
except Exception:
with print_lock:
print('Server is disconnected')
def threader():
p1 = threading.Thread(target = reciever)
p1.start()
p2 = threading.Thread(target = sender)
p2.start()
p1.join()
p2.join()
conn()
threader()
I have this script and it does work it has 2 separate processes that spawn listener threads to kill the process when kill is sent to the listener via a pipe.
from multiprocessing import Process, Pipe
from threading import Thread
import time
subAlive = True
testAlive = True
def sub_listener(conn): #listens for kill from main
global subAlive
while True:
data = conn.recv()
if data == "kill":
subAlive = False #value for kill
break
def test_listener(conn): #listens for kill from main
global testAlive
while True:
data = conn.recv()
if data == "kill":
testAlive = False #value for kill
break
def subprocess(conn, threadNum):
t = Thread(target=sub_listener, args=(conn,))
count = 0
threadVal = threadNum
t.start()
while subAlive:
print "Thread %d Run number = %d" % (threadVal, count)
count = count + 1
def testprocess(conn, threadNum):
t = Thread(target=test_listener, args=(conn,))
count = 0
threadVal = threadNum
t.start()
while testAlive:
print "This is a different thread %d Run = %d" % (threadVal, count)
count = count + 1
sub_parent, sub_child = Pipe()
test_parent, test_child = Pipe()
runNum = int(raw_input("Enter a number: "))
threadNum = int(raw_input("Enter number of threads: "))
print "Starting threads"
for i in range(threadNum):
p = Process(target=subprocess, args=(sub_child, i))
p.start()
print "Subprocess started"
for i in range(threadNum):
p2 = Process(target=testprocess, args=(test_child, i))
p2.start()
print "Testproccess started"
print "Starting run"
time.sleep(runNum)
print "Terminating Subprocess run"
for i in range(threadNum):
sub_parent.send("kill") #sends kill to listener
print "Terminating Testprocess run"
for i in range(threadNum):
test_parent.send("kill") #sends kill to listener
p.join()
p2.join()
Id like to not need a separate listener function hard coded for every process I call. I was thinking about passing global variables when the thread is spawned. The global variables are really the only differences between the listener functions. Thanks guys!
You can access globals through the globals() dictionary.
>>> foo = 'value'
>>> def change(name):
... globals()[name] = 'changed'
...
>>> change('foo')
>>> foo
'changed'
but I would suggest:
alive = {}
def sub_listener(conn, key): #listens for kill from main
while True:
data = conn.recv()
if data == "kill":
alive[key] = False #value for kill
break
e.g.
from multiprocessing import Process, Pipe
from threading import Thread
import time
alive = {
'sub': 1,
'test': 1,
}
def listener_factory(key):
def listener(conn): #listens for kill from main
while True:
data = conn.recv()
if data == "kill":
alive[key] = False #value for kill
break
return listener
def process_factory(key):
listener = listener_factory(key)
def subprocess(conn, threadNum):
t = Thread(target=listener, args=(conn,))
count = 0
threadVal = threadNum
t.start()
while alive[key]:
print "Thread[%s] %d Run number = %d" % (key, threadVal, count)
count = count + 1
return subprocess
def main():
sub_parent, sub_child = Pipe()
test_parent, test_child = Pipe()
runNum = int(raw_input("Enter a number: "))
threadNum = int(raw_input("Enter number of threads: "))
print "Starting threads"
for i in range(threadNum):
p = Process(target=process_factory('sub'), args=(sub_child, i))
p.start()
print "Subprocess started"
for i in range(threadNum):
p2 = Process(target=process_factory('test'), args=(test_child, i))
p2.start()
print "Testproccess started"
print "Starting run"
time.sleep(runNum)
print "Terminating Subprocess run"
for i in range(threadNum):
sub_parent.send("kill") #sends kill to listener
print "Terminating Testprocess run"
for i in range(threadNum):
test_parent.send("kill") #sends kill to listener
p.join()
p2.join()
if __name__ == '__main__':
main()