Python - nonblocking write to subprocess.PIPE? - python

I' developing with python for a Raspberry Pi video application. I modified a c-program that plays full hd movies to take input from a FIFO.
Like so:
$ ./hello_video.bin test.h264 < .my_fifo
$ echo 3 > .my_fifo
I can send numbers to the FIFO and the hello_video.bin will trigger the corresponding video clip and loop it forever.
Next step should be to make the videos triggerable from remote. This is what i have:
#!/usr/bin/env python
import socket
import threading
import Queue
import subprocess
import sys
from time import sleep
host = '' # empty port = all local ports
port = 5005
buffer = 2 # small buffer sufficient
player = "/opt/vc/src/hello_pi/hello_video/hello_video.bin"
clip = "/opt/vc/src/hello_pi/hello_video/test.h264"
p = subprocess.Popen([player, clip], stdin=subprocess.PIPE)
class readFromUDPSocket(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
data,addr = socketUDP.recvfrom(buffer)
try:
p.stdin.write(data)
p.stdin.flush()
except:
pass
if __name__ == '__main__':
# Create socket (IPv4 protocol, datagram (UDP)) and bind to address
socketUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socketUDP.bind((host, port))
# Instantiate & start threads
myServer = readFromUDPSocket()
myServer.daemon = True
myServer.start()
while 1:
pass
UDPSock.close()
Unfortunately the hello_video.bin doesn't react as supposed to. The commands do not trigger any other video.
I tried to use p.communicate(input=data) instead. This works, but just once. Then it blocks and i can't receive any other data from the socket.
I have no clue how to fix this — hope you can help me,
Thank you

Related

How to receive messages without pressing enter in socket programming

I'm new to socket programming in Python and I'm trying to write a chatroom application, but I have a problem which is it each client should press enter in order to receive messages from other clients.
#my client side code
import socket
import sys
client_sock = socket.socket()
port = int(sys.argv[1])
client_sock.connect(('127.0.0.1', port))
print("Connected to server. start sending messages")
while True:
sending_message = input('> ')
if sending_message:
client_sock.send(sending_message.encode())
receiving_message = client_sock.recv(1024)
if receiving_message:
print(receiving_message.decode())
input pauses your program. Thus, either you can't use input blindly, or you have to use threads. Using threads is easier than the alternative (using select to figure out what to do next). Have one thread for input and sending, one thread for receiving and printing.
Here's a trivial rewrite of your code:
import threading
import socket
import sys
client_sock = socket.socket()
port = int(sys.argv[1])
client_sock.connect(('127.0.0.1', port))
print("Connected to server. start sending messages")
def sender():
while True:
sending_message = input('> ')
if sending_message:
client_sock.send(sending_message.encode())
def receiver():
while True:
receiving_message = client_sock.recv(1024)
if receiving_message:
print(receiving_message.decode())
sender_thread = threading.Thread(target=sender)
receiver_thread = threading.Thread(target=receiver)
sender_thread.start()
receiver_thread.start()
sender_thread.join()
receiver_thread.join()

How to swap a string between two running python programs?

I want to swap an image generated by a python program to another running python program by using a string.
(I have to use a string because in the real application the string is coming from a C-program and not a python program but that doesn't matter)
So with one program I have to read what the other printed in the console.
But like I did it now, it don't work, the image is not correctly transmitted when I run the two programs in parallel, the image is just gray, so the reader string is not similar to the printed string.
Where is my mistake here?
Sender Program:
import time
from PIL import Image
import sys
image = Image.open("t.png")
while True:
print(image.tobytes())
time.sleep(5)
Receiver Program:
import os
import sys
from PIL import Image
from subprocess import Popen, PIPE, STDOUT
script_path = os.path.join('lsend.py')
p = Popen([sys.executable, '-u', script_path],
stdout=PIPE, stderr=STDOUT, bufsize=1)
while True:
string = p.stdout.readline()
print("image received !!!")
print(string[0:10])
try:
image = Image.frombytes('RGBA',(90, 36),string,"raw")
image.show()
except:
print("fail")
My Image:
my test image
Thanks for your answers!
I think there are two issues with your code:
there is no message boundary - the sender just sends a continuous stream of bytes and the receiver has no idea where one image ends and the next begins, and
Image.tobytes() seems to want to pair up with Image.frombuffer() rather than Image.frombytes() - no idea why!
So, I made your sender just send a single image and your receiver just receive a single image. I guess you would want to put some protocol on top that says how many bytes are coming, then the receiver would stop after receiving one image and start expecting a new byte count.
Here's lsend.py:
#!/usr/bin/env python3
import sys
from PIL import Image
image = Image.open('lora.png').convert('RGB')
sys.stdout.buffer.write(image.tobytes())
And here is receiver.py:
#!/usr/bin/env python3
import os
import sys
from PIL import Image
from subprocess import Popen, PIPE, STDOUT, DEVNULL
process = Popen(['./lsend.py'], stdout=PIPE, stderr=DEVNULL)
stdout, _ = process.communicate()
try:
image = Image.frombuffer('RGB',(90,36),stdout)
image.show()
except:
print("fail")
If the end result is to transmit video, I would recommend using sockets.
Python should provide everything you need in the socket library
This should give a general idea of how sending data over a socket works:
sender.py
import socket
# Host the socket on localhost for this example.
# This could send over a network too though.
host = "0.0.0.0"
port = 8000
# Initialize the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((host, port))
# The number of connections to listen for.
sock.listen(5)
print("Server listening.")
while True:
try:
# Accept an incoming connection from the client.
client, addr = sock.accept()
print("Accepted connection from client.")
# Wait until the client sends data.
data = client.recv(1024)
print(data)
# Send some data back to the client.
s = "Hello client"
client.send(s.encode())
client.close()
except KeyboardInterrupt:
break
Connecting to the socket is similar to hosting it. Instead of calling socket.bind, just call the socket.connect, and remove the socket.listen.
receiver.py
import socket
# The host and port the socket is hosted on.
host = "0.0.0.0"
port = 8000
# Create the socket and connect to the server.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
# Send the server some data.
s = "Hello server"
sock.send(s.encode())
# And receive some back.
data = sock.recv(1024)
print(data)

Multiple TCP to Serial connections python attempt.

So I'm trying to create a python script that will allow multiple TCP connections from different computers and allow talking over the serial from the TCP client. Here is what I was playing with
import sys
import os
import time
import fileinput
import socket
import serial
import thread
serialData = serial.Serial('/dev/ttyS0',9600)
import argparse
def on_new_client(clientsocket,addr):
while True:
msg = clientsocket.recv(1024)
#do some checks and if msg == someWeirdSignal: break:
print addr, ' >> ', msg
serialData.write(msg)
#msg = raw_input('SERVER >> ')
#Maybe some code to compute the last digit of PI, play game or
anything else can go here and when you are done.
clientsocket.send(msg)
clientsocket.close()
def on_Send_client(clientsocket,addr):
while True:
x = serialData.readline()
clientsocket.send(x)
clientsocket.close()
s = socket.socket()
host = '' #ip of raspberry pi
port = 12345
s.bind((host, port))
s.listen(5)
serialData.isOpen()
serialData.write("This is a test")
while True:
c, addr = s.accept()
thread.start_new_thread(on_new_client,(c,addr))
#thread.start_new_thread(on_Send_client,(c,addr))
s.close()
Right now I can connect with multiple TCP clients and eco their data. Their data also gets sent out the serial port. How should I go about buffering the serial data and sending it back out any and all connections that are active? Seems like nothing I look for online can do this correctly and Socat command even fails for multiple connections to serial.

Python Port Scanner with Threading

I am trying to create a port scanner in Python. I got the scanner going but it takes forty five minutes to print results. I started to institute threading however I can't figure out how to put different ranges into the script. I started to go to creating a global variable and try to pass that along in each thread. Unfortunately it's not working correctly and I am getting an invalid syntax error. Below is the code.
import socket
import os
import sys
from threading import Thread
server = raw_input("Please enter a server name ")
def portConnect():
global num
try:
serv_ip = socket.gethostbyname(server) # connects to server through try
print "Please wait, scanning remote host", serv_ip
for port in range(num):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = sock.connect_ex((serv_ip, port))
if connect == 0:
print "Port {}: Open".format(port)
sock.close()
except socket.gaierror:
print """
I can't find that server, idiot! Try again
"""
sys.exit()
for i in range(1):
t = Thread(target=portConnect,(num=100))
t.start()
What am I doing wrong?
Thread expects args= as tuple and it sends it as arguments to function
This way you send 100 as first argument (num) to portConnect()
def portConnect(num):
print(num)
# code
t = Thread(target=portConnect, args=(100,) )
To send range you need two arguments
def portConnect(from_, to_):
print(from_, to_)
for port in range(from_, to_):
# ...
size = 20
for i in range(1, 100, size):
t = Thread(target=portConnect, args=(i, i+size))
t.start()
BTW: module scapy lets you send single packet so it is used for portscanning, sniffing, etc.
You can do more with special tools like nmap (GUI wrapper: Zenmap) or Kali Linux
You may try to use nmap in Python: python-nmap : nmap from python
you can solve this really easily using nmap.
nmap -p- <some_host>

Implementing Multi-Threading in a Python Script

I wanted to create a python script to stress test my servers.
So I created this basic UDP flooder and I think I have it working correctly.
My question is how would I go about adding multi-threading to this?
I read a manual on Python threading but didn't understand how to actually
implement it into my script.
import socket
import random
print "Target:",
ipaddr = raw_input()
sent = 1
bytes = random._urandom(10000)
port = 1
while sent > 0:
print "Test Started On", ipaddr, "|", sent, "Packets Sent. Press Ctrl+C To Stop."
sent += 1
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(bytes,(ipaddr,port))
port = random.randint(1, 65500)
raw_input()
If you extract the business part of your application into a function like:
def do_the_flooding():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(bytes,(ipaddr,port))
You can then call it in a thread:
import threading
t = threading.Thread(target=do_the_flooding)
t.start()

Categories