How to swap a string between two running python programs? - python

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)

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()

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 connect socket to process

I have a (very) simple web server I wrote in C and I want to test it. I wrote it so it takes data on stdin and sends out on stdout. How would I connect the input/output of a socket (created with socket.accept()) to the input/output of a process created with subprocess.Popen?
Sounds simple, right? Here's the killer: I'm running Windows.
Can anyone help?
Here's what I've tried:
Passing the client object itself as stdin/out to subprocess.Popen. (It never hurts to try.)
Passing socket.makefile() results as stdin/out to subprocess.Popen.
Passing the socket's file number to os.fdopen().
Also, in case the question was unclear, here's a slimmed-down version of my code:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', PORT))
sock.listen(5)
cli, addr = sock.accept()
p = subprocess.Popen([PROG])
#I want to connect 'p' to the 'cli' socket so whatever it sends on stdout
#goes to the client and whatever the client sends goes to its stdin.
#I've tried:
p = subprocess.Popen([PROG], stdin = cli.makefile("r"), stdout = cli.makefile("w"))
p = subprocess.Popen([PROG], stdin = cli, stdout = cli)
p = subprocess.Popen([PROG], stdin = os.fdopen(cli.fileno(), "r"), stdout = os.fdopen(cli.fileno(), "w"))
#but all of them give me either "Bad file descriptor" or "The handle is invalid".
I had the same issue and tried the same way to bind the socket, also on windows. The solution I came out with was to share the socket and bind it on the process to stdin and stdout. My solutions are completely in python but I guess that they are easily convertible.
import socket, subprocess
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', PORT))
sock.listen(5)
cli, addr = sock.accept()
process = subprocess.Popen([PROG], stdin=subprocess.PIPE)
process.stdin.write(cli.share(process.pid))
process.stdin.flush()
# you can now use `cli` as client normally
And in the other process:
import sys, os, socket
sock = socket.fromshare(os.read(sys.stdin.fileno(), 372))
sys.stdin = sock.makefile("r")
sys.stdout = sock.makefile("w")
# stdin and stdout now write to `sock`
The 372 is the len of a measured socket.share call. I don't know if this is constant, but it worked for me. This is possible only in windows, as the share function is only available on that OS.

Python - nonblocking write to subprocess.PIPE?

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

Python client-server script hangs until I press [enter]

I have a basic client-server script in Python using sockets. The server binds to a specific port and waits for a client connection. When a client connects, they are presented with a raw_input prompt that sends the entered commands to a subproc on the server and pipes the output back to the client.
Sometimes when I execute commands from the client, the output will hang and not present me with the raw_input prompt until I press the [enter] key.
At first I thought this might have been a buffer problem but it happens when I use commands with a small output, like 'clear' or 'ls', etc.
The client code:
import os, sys
import socket
from base64 import *
import time
try:
HOST = sys.argv[1]
PORT = int(sys.argv[2])
except IndexError:
print("You must specify a host IP address and port number!")
print("usage: ./handler_client.py 192.168.1.4 4444")
sys.exit()
socksize = 4096
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.connect((HOST, PORT))
print("[+] Connection established!")
print("[+] Type ':help' to view commands.")
except:
print("[!] Connection error!")
sys.exit(2)
while True:
data = server.recv(socksize)
cmd = raw_input(data)
server.sendall(str(cmd))
server.close()
Server code:
import os,sys
import socket
import time
from subprocess import Popen,PIPE,STDOUT,call
HOST = ''
PORT = 4444
socksize = 4096
activePID = []
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.bind((HOST, PORT))
conn.listen(5)
print("Listening on TCP port %s" % PORT)
def reaper():
while activePID:
pid,stat = os.waitpid(0, os.WNOHANG)
if not pid: break
activePID.remove(pid)
def handler(connection):
time.sleep(3)
while True:
cmd = connection.recv(socksize)
proc = Popen(cmd,
shell=True,
stdout=PIPE,
stderr=PIPE,
stdin=PIPE,
)
stdout, stderr = proc.communicate()
if cmd == ":killme":
connection.close()
sys.exit(0)
elif proc:
connection.send( stdout )
connection.send("\nshell => ")
connection.close()
os._exit(0)
def accept():
while 1:
global connection
connection, address = conn.accept()
print "[!] New connection!"
connection.send("\nshell => ")
reaper()
childPid = os.fork() # forks the incoming connection and sends to conn handler
if childPid == 0:
handler(connection)
else:
activePID.append(childPid)
accept()
The problem I see is that the final loop in the client only does one server.recv(socksize), and then it calls raw_input(). If that recv() call does not obtain all of the data sent by the server in that single call, then it also won't collect the prompt that follows the command output and therefore won't show that next prompt. The uncollected input will sit in the socket until you enter the next command, and then it will be collected and shown. (In principle it could take many recv() calls to drain the socket and get to the appended prompt, not just two calls.)
If this is what's happening then you would hit the problem if the command sent back more than one buffer's worth (4KB) of data, or if it generated output in small chunks spaced out in time so that the server side could spread that data over multiple sends that are not coalesced quickly enough for the client to collect them all in a single recv().
To fix this, you need have the client do as many recv() calls as it takes to completely drain the socket. So you need to come up with a way for the client to know that the socket has been drained of everything that the server is going to send in this interaction.
The easiest way to do this is to have the server add boundary markers into the data stream and then have the client inspect those markers to discover when the final data from the current interaction has been collected. There are various ways to do this, but I'd probably have the server insert a "this is the length of the following chunk of data" marker ahead of every chunk it sends, and send a marker with a length of zero after the final chunk.
The client-side main loop then becomes:
forever:
read a marker;
if the length carried in the marker is zero then
break;
else
read exactly that many bytes;.
Note that the client must be sure to recv() the complete marker before it acts on it; stuff can come out of a stream socket in lumps of any size, completely unrelated to the size of the writes that sent that stuff into the socket at the sender's side.
You get to decide whether to send the marker as variable-length text (with a distinctive delimiter) or as fixed-length binary (in which case you have to worry about endian issues if the client and server can be on different systems). You also get to decide whether the client should show each chunk as it arrives (obviously you can't use raw_input() to do that) or whether it should collect all of the chunks and show the whole thing in one blast after the final chunk has been collected.

Categories