I have this code, which listens for a command 'Updated Playlist' over sockets.
When it gets this command, it knows that the playlist in the database has been updated and it connects to the database and downloads the new playlist and then it starts playing these files.
I'm trying to find the best way about this because when it gets the command, then calls the Media_Player function, it will play all the videos in the playlist before it returns to listen to the sockets.
In the mean time if another 'Updated Playlist' command has been sent, the sender of this command gets an error because this code won't be listening. I want the media player to be playing non stop, but it also has to be listening constantly in case it has been told a new play list has been added.
Then if a new playlist has been added, it will know and when one of the files in the play list has finished playing it can switch over to the new playlist and keep going.
I don't know how to go about this, I thought I could have it all in the one process and just spawn off a new thread for each file in the play list, so it can go straight back to listening, but then how am I suppose to know when the thread has finished because each file in the playlist will be different lengths.
Also in the function listen_serv() see the line 'return data', does this mean its not closing the connection because its returning?
# Echo server program
import socket
import time
import Database as DB
def listen_serv():
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
conn.sendall('OK')
return data
conn.close()
while 1:
val= listen_serv()
if val=='Updated Playlist':
PlayList = DB.get_play_list()
Media_Player(PlayList)#This isnt implemented yet
You could have two processes running one is the server and the other is the MediaPlayer with a Queue in between.
The server pushes commands onto the queue where the MediaPlayer pops them, after playing each video simply check if theres anything on the queue, if there is pop it and play the new playlist.
import socket
import time
import Database as DB
from multiprocessing import Process, Queue
def listen_serv(queue):
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data:
break
conn.sendall('OK')
queue.put(data)
conn.close()
def media_player(queue):
while 1:
val = queue.get() # This will block until theres something on the queue.
if val == 'Updated Playlist':
PlayList = DB.get_play_list()
Media_Player(PlayList, queue) # Media_Player needs to check the queue and update when appropriate.
if __name__ == '__main__':
q = Queue()
server = Process(target = listen_serv, args = (q,))
media_player = Process(target = media_player, args = (q,))
server.start()
media_player.start()
server.join()
media_player.join()
you can check if the queue is empty by queue.empty()
Im sure there are better implementations out there, if there are bugs/issues I apologize.
good luck.
Related
I have been trying to make a server where multiple people can connect but i keep getting stuck on one problem. Allowing the server to listen to a client while the server host is still able to type in commands.
running = True
while running:
command = input('>> ') # Allow for inputs but still connect new users (ex, a minecraft server)
conn, addr = self.server.accept()
print(f"[NEW CONNECTION] {conn}:{addr}")
thread = threading.Thread(target=self.clientThread, args=(conn, addr))
thread.start()
In short it listens for new connections or allows inputs but it never does both... I know i can do this by running it in different cmd's but it would be way better to keep it all in one place.
you could create a ClientHandler or create two methods. smth like this:
def connecting_users():
# accept connections
thread = threading.Thread(target=server_commands,)
thread.start()
while True:
conn, addr = server.accept()
# do your stuff
def server_commands():
while True:
command = input......
Note that this is not tested
Hello I tried to make a simple server that accept multiple clients simultaneously I'm new to python and I have a difficult to understand it....I try to change my code in multi-thread applications but without positive result...here is the code:
import socket, threading
def message():
while 1:
data = connection.recv(1024)
if not data: break
#connection.sendall(b'-- Message Received --\n')
print(data.decode('utf-8'))
connection.close()
def connection():
address = input("Insert server ip")
port = 44444
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.listen(1)
print("Server started! Waiting for connections...")
def accept connection():
connection, address = s.accept()
print('Client connected with address:', address)
t=thread.Threading(target=message,args=(connection))
t.run()
I know that there are many errors but I'm new in python sorry :(
The original non-threaded code is:
import socket
address = input("Insert server ip:")
port = 44444
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.listen(1)
print("Server started! Waiting for connections...")
connection, address = s.accept()
print('Client connected with address:', address)
while 1:
data = connection.recv(1024)
if not data: break
#connection.sendall(b'-- Message Received --\n')
print(data.decode('utf-8'))
connection.close()
Your basic design is close, but you've got a whole lot of little problems making it hard to move forward.
First, you have a function name with a space in it, which isn't allowed. And you have an IndentationError because you didn't indent its contents.
Next, inside that accept_connection function, you're using threading wrong.
thread.Threading doesn't exist; you probably meant threading.Thread.
args has to be a sequence (tuple, list, etc.) of values. You probably expected (connection) to be a tuple of one value, but it's not; tuples are defined by commas, not parentheses, and what you have is just the value connection with superfluous parentheses around it. You wanted (connection,) here.
Also, calling run on a thread object just runs the thread's code in the current thread. You want to call start, which will start a new thread and call the run method on that thread.
Meanwhile, you're never actually calling this function anywhere, so of course it can't do anything. Think about where you want to call it. After creating the listener socket, you want to loop around accept, kicking off a new client thread for each accepted connection, right? So, you want to call it in a loop, either inside connection, or at the top level (in which case connection has to return s).
And finally, your accept_connection function can't access local variables from some other function; if you want it to use a socket named s, you have to pass it as a parameter.
So:
def connection():
address = input("Insert server ip")
port = 44444
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((address, port))
s.listen(1)
print("Server started! Waiting for connections...")
while True:
accept_connection(s)
def accept_connection(s):
connection, address = s.accept()
print('Client connected with address:', address)
t=thread.Threading(target=message, args=(connection,))
t.start()
As a side note, be careful with using sock.recv(1024) and assuming you're going to get the whole message that the other side sent with send(msg). You might get that, or you might get half the message, or the whole message plus half of another message the client sent later. Sockets are just streams of bytes, like files, not streams of separate messages; you need some kind of protocol to separate messages.
The simplest possible protocol is to send each message on its own line. Then you can just do socket.makefile() and for line in f:, just like you would for a real file. Of course this doesn't work if your messages can have newlines, but you can, e.g., backslash-escape them on one side and unescape them on the other.
This is a pretty old post but there's a nice way to do what you're talking about. Here's a link to an example I posted a little while back:
https://bitbucket.org/matthewwachter/tcp_threadedserver/src/master/
And the script:
from datetime import datetime
from json import loads, dumps
from pprint import pprint
import socket
from threading import Thread
class ThreadedServer(Thread):
def __init__(self, host, port, timeout=60, debug=False):
self.host = host
self.port = port
self.timeout = timeout
self.debug = debug
Thread.__init__(self)
# run by the Thread object
def run(self):
if self.debug:
print(datetime.now())
print('SERVER Starting...', '\n')
self.listen()
def listen(self):
# create an instance of socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# bind the socket to its host and port
self.sock.bind((self.host, self.port))
if self.debug:
print(datetime.now())
print('SERVER Socket Bound', self.host, self.port, '\n')
# start listening for a client
self.sock.listen(5)
if self.debug:
print(datetime.now())
print('SERVER Listening...', '\n')
while True:
# get the client object and address
client, address = self.sock.accept()
# set a timeout
client.settimeout(self.timeout)
if self.debug:
print(datetime.now())
print('CLIENT Connected:', client, '\n')
# start a thread to listen to the client
Thread(target = self.listenToClient,args = (client,address)).start()
# send the client a connection message
# res = {
# 'cmd': 'connected',
# }
# response = dumps(res)
# client.send(response.encode('utf-8'))
def listenToClient(self, client, address):
# set a buffer size ( could be 2048 or 4096 / power of 2 )
size = 1024
while True:
try:
# try to receive data from the client
data = client.recv(size).decode('utf-8')
if data:
data = loads(data.rstrip('\0'))
if self.debug:
print(datetime.now())
print('CLIENT Data Received', client)
print('Data:')
pprint(data, width=1)
print('\n')
#send a response back to the client
res = {
'cmd': data['cmd'],
'data': data['data']
}
response = dumps(res)
client.send(response.encode('utf-8'))
else:
raise error('Client disconnected')
except:
if self.debug:
print(datetime.now())
print('CLIENT Disconnected:', client, '\n')
client.close()
return False
if __name__ == "__main__":
ThreadedServer('127.0.0.1', 8008, timeout=86400, debug=True).start()
Here is some example code I have showing a threaded socket connection.
def sock_connection( sock, host ):
"Handle socket"
pass
while 1:
try:
newsock = sock.accept()
thread = Thread( target=sock_connection, args=newsock )
thread.start()
except Exception, e:
print "error on socket connection: " % e)
I keep on receiving this error of 1 - 3 arguments needing to be sequences
import socket # Import socket module
import sys
import select
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a socket object
host = "127.0.0.1" # Get local machine name
port = 50001 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
a = []
b = []
s.listen(1) # Now wait for client connection.
c, addr = s.accept() # Establish connection with client.
s.setblocking(0)
ready = select.select(s, s, s, 1) # i believe the error lies in here
while True:
print "reached"
if ready[0]:
print "reached1"
data = mysocket.recv(4096)
print 'Got connection from', addr
c.send('Thank you for connecting \r\n') #all strings have to end with /r/n!!!
print "sent"
c.close() # Close the connection
Error
Select.select arguments 1 - 3 has to be sequences.
I am new to python and hence i am unsure of what the error is. I googled the select code from another post as i wanted my recv socket to be non blocking
select.select takes three lists as arguments, rlist, wlist and xlist:
rlist: wait until ready for reading
wlist: wait until ready for writing
xlist: wait for an “exceptional condition” (see the manual page for what your system considers such a condition)
You're not passing lists but single sockets.
Try this:
ready = select.select([s], [s], [s], 1)
The return value will, again, be a tuple of three lists, the first containig sockets ready for reading, the second sockets ready for writing and the third sockets in 'exceptional condition'.
Note also that in your while loop you never update ready, so you will always use the same lists of sockets. Also, you should have a break somewhere, otherwise you'll end up calling c.send in an endless loop.
I'm having a little trouble with sockets in Python. Whenever someone connects it works fine but if they disconnect the server program closes. I want the server program to remain open after the client closes. I'm using a while True loop to keep the connection alive but once the client closes the connection the server closes it's connection.
Here is the client:
import socket, sys
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1]
port = int(sys.argv[2])
conn.connect((host, port))
print("Connected to host " + sys.argv[1])
td = 1
while td == 1:
msg = raw_input('MSG: ')
Here is the server:
import socket, sys
socket.setdefaulttimeout(150)
host = ''
port = 50005
socksize = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("Server started on port: %s" % port)
s.listen(1)
print("Now listening...\n")
conn, addr = s.accept()
while True:
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
if not data:
break
elif data == 'killsrv':
conn.close()
sys.exit()
else:
print(data)
If a client closes a connection, you want it to close the socket.
It seems like there's a bit of a disconnect here that I'll try to elaborate on. When you create a socket, bind, and listen, you've established an open door for others to come and make connections to you.
Once a client connects to you, and you use the accept() call to accept the connection and get a new socket (conn), which is returned for you to interact with the client. Your original listening socket is still there and active, and you can still use it to accept more new connections.
Looking at your code, you probably want to do something like this:
while True:
print("Now listening...\n")
conn, addr = s.accept()
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
if not data:
break
elif data == 'killsrv':
conn.close()
sys.exit()
else:
print(data)
Please note that this is just a starting point, and as others have suggested you probably want to use select() along with forking off processes or spawning threads to service each client.
Your code is only accepting a single connection - the loop only deals with the first accepted connection and terminates as soon as it lost. This is way your server exists:
data = conn.recv(socksize)
if not data:
break
What you will need to do is to accept several connections, while handling each of those in it's own loop. Note that it does not have to be a real loop for each socket, you can use a select-based approach to query which of the sockets has an event associated with it (data available, connection lost etc.) and then process only those sockets, all in the same loop.
You can also use a multi threaded / multi process approach, dealing with each client in it's own thread or process - I guess you won't run into scaling issues when playing around.
See:
http://docs.python.org/library/select.html
http://docs.python.org/library/multiprocessing.html
I have a main thread that waits for connection. It spawns client threads that will echo the response from the client (telnet in this case). But say that I want to close down all sockets and all threads after some time, like after 1 connection.
How would I do it? If I do clientSocket.close() from the main thread, it won't stop doing the recv. It will only stop if I first send something through telnet, then it will fail doing further sends and recvs.
My code looks like this:
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocket):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
# It will hang here, even if I do close on the socket
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
time.sleep(1)
# This won't make the recv in the clientThread to stop immediately,
# nor will it generate an exception
clientSocket.close()
I know this is an old thread and that Samuel probably fixed his issue a long time ago. However, I had the same problem and came across this post while google'ing. Found a solution and think it is worthwhile to add.
You can use the shutdown method on the socket class. It can prevent further sends, receives or both.
socket.shutdown(socket.SHUT_WR)
The above prevents future sends, as an example.
See Python docs for more info.
I don't know if it's possible to do what you're asking, but it shouldn't be necessary. Just don't read from the socket if there is nothing to read; use select.select to check the socket for data.
change:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
to something more like this:
r, _, _ = select.select([self.clientSocket], [], [])
if r:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
EDIT: If you want to guard against the possibility that the socket has been closed, catch socket.error.
do_read = False
try:
r, _, _ = select.select([self.clientSocket], [], [])
do_read = bool(r)
except socket.error:
pass
if do_read:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
I found a solution using timeouts. That will interrupt the recv (actually before the timeout has expired which is nice):
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocke):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except socket.timeout:
# If it was a timeout, we want to continue with recv
continue
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
clientSocket.settimeout(1)
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
# Close it down immediatly
clientSocket.close()
I must apologize for the comments below. The earlier comment by #Matt Anderson works. I had made a mistake when trying it out which led to my post below.
Using timeout is not a very good solution. It may seem that waking up for an instant and then going back to sleep is no big deal, but I have seen it greatly affect the performance of an application. You have an operation that for the most part wants to block until data is available and thus sleep forever. However, if you want to abort for some reason, like shutting down your application, then the trick is how to get out. For sockets, you can use select and listen on two sockets. Your primary one, and a special shutdown one. Creating the shutdown one though is a bit of a pain. You have to create it. You have to get the listening socket to accept it. You have to keep track of both ends of this pipe. I have the same issue with the Synchronized Queue class. There however, you can at least insert a dummy object into the queue to wake up the get(). This requires that the dummy object not look like your normal data though. I sometimes wish Python had something like the Windows API WaitForMultipleObjects.