Blender API (bpy) and socket server - python

I am running blender with a python file via shell like this
./blender visualizer.blend -P Visualizer.py
in my python file I have a socket server, that receives a list and loops over the list to create meshes accordingly.
Now the problem is I have to use threading so that blender doesn't freeze because otherwise blender's window won't even show.
but from the socket thread as it appears I can not create meshes as it crashes my blender without throwing any exception. I have tried multiprocessing as well and it freezes blender.
now does anybody has any idea how to have socket server receive data and create meshes without freezing blender?
def socket_server(*args):
HOST = '127.0.0.1'
PORT = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
s.bind((HOST, PORT))
s.listen(5)
conn, addr = s.accept()
while 1:
data = conn.recv(16384)
if not data:
break
//creates mesh here
conn.send(b'ok')
time.sleep(1.0)
conn.close()
if __name__ == '__main__':
try:
t = Thread(None, socket_server)#crashes
t.start()
# socket_server() #freezes
# worker = mp.Process(target=socket_server()) #freezes
# worker.daemon = True
# worker.start()
except Exception as e:
print (e)

On blender API docs it clearly warns you not to use threading at all.
You can Create Operator and run it with timer event.
with timer event you can poll network messages from socket and perform any action.

I came to realize that blender needs time to finish drawing an object before asking it to draw another one. so all I had to do was to put time.sleep(1) in my loop for creating objects.

Related

A server that handles clients in the background while you can still type in commands

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

Python Scheduling jobs with schedule along with socket module not working

I am trying to create a sockets server (TCP/IP) and inside it based on few data from client I am scheduling few background jobs.
following code is working ->
import schedule
import time
def test1():
print('hi from 1')
def test2():
print('hi from test2')
while True:
schedule.run_pending()
time.sleep(1)
Then I tried following thing with socket server then its not executing the jobs/function. Can someone help me what's happening here.
Not working code
import schedule
import time
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 8009)
print('starting up on {} port {}'.format(*server_address))
sock.bind(server_address)
# Listen for incoming connections
sock.listen(1)
def test1():
print('hi from 1')
def test2():
print('hi from test2')
schedule.every(1).minutes.do(test1)
schedule.every(2).minutes.do(test2)
while True:
schedule.run_pending()
time.sleep(1)
print('waiting for a connection')
connection, client_address = sock.accept()
data = connection.recv(1024)
result = data.decode('utf-8')
print('data recived from clinet : ', result)
Thing I am trying to achieve is I want to create python socket server which
will accept request from node client's and based on clients data I want to schedule few jobs in python. for this I am using socket, schedule moduls from python to create socket server and schedule jobs respective and net module at node js's client for sending data to python server.
Please explain your problem in more detail. sock.accept is blocking, so the loop is blocking, is this your problem?
To prevent the program from blocking you can run the scheduler loop in a separate thread and the acceptance loop also in a separate thread too. Create a main thread to manage your child threads. Have a look at the module threading.
Maybe it makes sense to use an other scheduler library that can handle threading, see here.
Disclosure: I'm one of the authors of the scheduler library

sending data across two programs in python

This is my code:
socketcheck.py
import time
import subprocess
subprocess.Popen(["python", "server.py"])
for i in range(10):
time.sleep(2)
print i
def print_from_server(data):
print data
server.py
import socket
from socketcheck import print_from_server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost',3005))
client_connected = 1
while 1:
s.listen(1)
conn, addr = s.accept()
data = conn.recv(1024)
if data:
client_connected = 0
else: break
if client_connected == 0:
print 'data received'
print_from_server(data)
client_connected = 1
conn.sendall(data)
client.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost',3005))
s.sendall('Hello, world')
data = s.recv(1024)
#s.close()
print 'Received', repr(data)
What I am trying to do here is, run socketcheck.py which runs server.py in background and listens for a client connection. So whatever data the client sends, I want to pass it on to socketcheck.py. Is this valid? If so, then how do I achieve it?
Now when I try and run socketcheck.py, the for loop is running indefinitely.
Thanks :)
EDIT:
This initially I tried as a single program, but until the client gets connected, the rest of the program doesn't execute(blocking), with the setblocking(0) the program flow wouldn't stop but when the client connects to server it doesn't print(do anything). The server code looked something like this:
import socket
from socketcheck import print_from_server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost',3005))
s.setblocking(0)
while 1:
try:
s.listen(1)
conn, addr = s.accept()
conn.setblocking(0)
data = conn.recv(1024)
if not data: break
print 'data received'
conn.sendall(data)
except:
print 'non blocking'
print 'the lengthy program continues from here'
The reason why your program crashes your computer is simple:
You have a while loop which calls print_from_server(data), and each time it calls it, a new subprocess gets created via subprocess.Popen(["python", "server.py"]).
The reason for creating a new popen each time is a bit more complicated: You open a new server.py program in socketcheck.py. If this new server.py program calls print_from_server(data), this is the first time print_from_server(data) gets called (for the new server.py program). So the global commands (such as popen) are executed, since they are always executed once.
The number of processes running will explode quickly and you computer crashes.
One additional remark: You cannot print to console with a print command in a subprocess, since there is no console attached to that subprocess, you can only print to file. If you do that, you'll see that this output explodes quickly from all the processes.
Put socketcheck.py and server.py into one program and everything works fine, or explain why you need two programs.
The functionality can be easily achieved with multithreading :)

closing open socket in python

Im wondering is there any way to find out the socket that is open and then to close it?
For instance,I have a script "SendInfo.py" which opens a socket and sends some info over TCP.
If I call this script to run it e.g. "python SendInfo.py" , it will open a new socket.
If I run this script again using "python SendInfo.py", which will send some more up to date information, I would like to cancel the previous TCP transaction and start a new one - e.g. by closing the previous socket.
How do I get access to the open socket at the beginning of my script in order to close it? Ive tried looking into threads, but Im similarly confused about which threads are open and how to close open threads etc.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.settimeout(2)
s.connect((self.__host, PORT))
I'm not sure if this is what you are after but here is a method of ensuring that the script is only running once and killing an existing running script.
You may find something useful in it. (This is for Linux)
#!/usr/bin/python
# running.py
# execute by making the script executable
# put it somewhere on $PATH and execute via running.py
# or execute via ./running.py
import os, sys, time , signal, socket
running_pid = os.popen('ps --no-headers -C running.py').read(5)
try:
running_pid = int(running_pid)
except:
running_pid = 0
current_pid = int(os.getpid())
if running_pid != 0:
if running_pid != current_pid:
print "Already running as process", running_pid
print "Killing process", running_pid
os.kill(int(running_pid), signal.SIGKILL)
# sys.exit()
# Create a listening socket for external requests
tcp_port = 5005
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print "Error on Socket 5005"
# force re-use of the socket if it is in time-out mode after being closed
# other wise we can get bind errors after closing and attempting to start again
# within a minute or so
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sock.settimeout(0.10)
sock.bind(("localhost", tcp_port))
except IOError as msg:
print "Error on Socket Bind "+str(tcp_port)+", running.py is probably already running"
pass
try:
sock.listen((1))
except:
print "Error on Socket listen"
time.sleep(60)
sock.close()

Python code, should I thread? what to do?

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.

Categories