Sending multiple images with socket - python-3.x

In an ambitious attempt making a VNC with Python, I am trying to continuously send screenshots of one user (Server) to another (Client). After hours of trying and hitting Ballmer's peak, I managed to do it. However, now my problem is sending multiple images, a continuous stream of them. I first tried to write all the binary data to one file, which didn't work. When the second image was opened, it crashed. I thought this might be because the binary data somehow got corrupted, so instead I tried making a new file for every image, yet I have the same problem. I know that Tcp is a constant stream of data so that it would be hard to know the end of the first image and start of the next, but by creating another file, I thought I would be all good.
Any help in fixing this and/or increasing the efficiency of this is greatly appreciated :)
Server side:
import socket
from PIL import Image, ImageGrab
PORT = 10007
HOST = '127.0.0.1'
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
counter = 3
while counter > 0:
image = ImageGrab.grab(bbox=None)
image.save('test.png')
f = open('test.png', 'rb')
l = f.read(1024)
while (l):
conn.send(l)
l = f.read(1024)
f.close()
print('Done sending curr image')
counter -= 1
conn.close()
Client side:
import socket
from PIL import Image
HOST = '127.0.0.1'
PORT = 10007
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
counter = 1
while counter != 3:
fname = 'image' + str(counter) + '.png'
with open(fname, 'wb') as file:
print('file opened')
while True:
data = s.recv(1024)
if not data:
break
else:
file.write(data)
file.close()
currImg = Image.open(fname)
currImg.show()
counter += 1
s.close()

Your receiver does not know when one file finishes and the next begins. The easiest way to fix that is to send the length of the file (perhaps as a 4-byte unsigned value) to the receiver before sending each file. Then the receiver can read the length, read the file, read the length, read the file, ...
To improve efficiency you can stop saving the file data into an actual file at both ends and instead save it into (and, obviously, read it from) an in-memory buffer. See this answer for explanations of how to do that. In Python 3 it looks like you would use the BytesIO module.
Another improvement would be to only send image data for the parts of the screen that have changed since the previous send. For that you'll need to figure out how to compare the current capture against the previous one. For a first pass you could use PIL.ImageChops.difference followed by PIL.Image.getbbox and then encode and send only that region of the current capture. For that to work, the sender will have to tell the receiver not only the size of the PNG but also the location in the output screen image where the new image patch should be painted. So you'll want to send a position in addition to the size and the encoded image data.

Related

how to handle when client sends more bytes than we can store and the buffer gets overwritten?

We have a socket in python3 that receive x bytes from client, our problem lies when the client sends more bytes than x, when this happens our buffer gets overwritten and we lose previous bytes. We need a way to avoid lose the first bytes. We'll appreciate any help. Thanks!
class Connection(object):
def __init__(self, socket, directory):
self.sock = socket
self.directory = directory
def handle(self):
while(True):
data = self.sock.recv(4096)
if len(data) > 0:
...
we expect to stop the socket from receving or some way to avoid losing the bytes that we already have in the buffer
You could do the following:
def receivallData(sock, buffer_size=4096):
buf = sock.recv(buffer_size)
while buf:
yield buf
if len(buf) < buffer_size: break
buf = sock.recv(buffer_size)
You can read more on this here:
Python Socket Receive Large Amount of Data
you can follow this logic:
create a buffer in which you store all the receive data
append the data you receive at each iteration of the loop to this buffer so you won't lose it
check if you receive the full data in order to process it
The example below explains how to create the buffer and append the data to it (in the example I exit the loop if no more data is available on the socket or socket closed)
total_data = []
while True:
data = self.sock.recv(4096)
if not data:
break
total_data.append(data)
# TODO: add processing on total_data
print "".join(total_data)

Not able to create new variable and send as udp in the same socket

I am trying to send some data from android to python server then want to run some functions and send the data back to android. Android code is working fine, but my program ignore the lines where I am creating new variables and sending the data. I am using python3.
The particular line is num = random.randint(1,100)
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSock.bind(("", UDP_PORT))
def userrec(addr):
num = random.randint(1,100)
result = num.encode("utf-8")
serverSock.sendto(result, addr)
while True:
data, addr = serverSock.recvfrom(1024)
message = data.decode("utf-8")
if data:
userrec(addr)
serverSock.close()
Can't we create new variables or run some function after recieving the data?
Found the solution. I just have to remove ServerSock.close()

Python3 non-blocking recv

I trying to do a simple server. The server has to load data while client provides it. I want to use non-blocking 'recv' command, but whatever I do it still blocks. My code is above.
import socket
import fcntl
import os
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("localhost", 8888))
server_socket.listen()
client_socket, addr = server_socket.accept()
#fcntl.fcntl(client_socket, fcntl.F_SETFL, os.O_NONBLOCK) #mark1
client_socket.setblocking(False) #mark2
#client_socket.settimeout(0.0) #mark3
while True:
data = client_socket.recv(10)
if len(data) != 0:
print(data.decode("UTF8"))
else:
break
print("Exit")
I tried to use lines '#mark1', '#mark2', '#mark3'. These lines seem to be pretty good for me, but my program is still stuck on the second iteration with data = client_socket.recv(10) line.
Why do client_socket.setblocking(False) and others not affect?

Python3 socket cannot decode content

I'm facing a strange issue. I cannot decode the data received through a socket connection while it's working with the same code in python 2.7. I know that the data type received in python 2 is a string an bytes in python 3. But I don't understand why I'm receiving an error when I try to decode.
I'm sending exactly the same datas(copy/paste to be sure) except that I need to perform .encode() for python 3 to avoid to received "TypeError, a bytes-like object is required, not 'str' "
Python2:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(15)
s.connect((SERVERIP, SERVERPORT))
s.send(message)
data = ''
while True:
new_data = s.recv(4096)
if not new_data:
break
data += new_data
s.close()
Python 3
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(15)
s.connect((SERVERIP, SERVERPORT))
s.send(message)
data = ''
while True:
new_data = s.recv(4096)
if not new_data:
break
data += new_data.decode('utf-8') #same result with new_data.decode()
s.close()
Python 2 new_data content:
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x00\x05\xc1\xdd\x12B#\x18\x00\xd0\x07r\xa3\xb6\xfdv]t\xa1T&\xb5d\x91\xd1tA\x98]F\xfeB\x1a\x0f\xdf9yu\x10s\xa3\xa29:\xdbl\xae\xe9\xe8\xd9H\xc8v\xa8\xd0K\x8c\xde\xd7\xef\xf9\xc4uf\xca\xfd \xdd\xb7\x0c\x9a\x84\xe9\xec\xb7\xf1\xf3\x97o\\k\xd5E\xc3\r\x11(\x9d{\xf7!\xdc*\x8c\xd5\x1c\x0b\xadG\xa5\x1e(\x97dO\x9b\x8f\x14\xaa\xddf\xd7I\x1e\xbb\xd4\xe7a\xe4\xe6a\x88\x8b\xf5\xa0\x08\xab\x11\xda\xea\xb8S\xf0\x98\x94\x1c\x9d\xa24>9\xbai\xd3\x1f\xe6\xcc`^\x91\xca\x02j\x1aLy\xccj\x0fdVn\x17#\xb0\xc1#\x80hX#\xb0\x06\n\x0b\xc0\xf2x\xfe\x01?\x05\x1f\xc1\xc5\x00\x00\x00'
Python3 new_data content:
b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x00\x05\xc1\xdb\x12B#\x00\x00\xd0\x0f\xf2\xc0\xda\xb5\xcbC\x0f"-\xb9gPM\x0f\x85&\x8b)\xb7\x1d\x1a\x1f\xdf9\xe3\xbc\xbe\xfd\x9e\xd9A\xe3:\x851,\xcf\xc4\xe5\x865|\xa5\xcb\xbb\xcbs\xa8\x8f\xcc\x1b\xf7\x06\xc5\x8f\xfa\xba\x84\xd8>\xea\xc0\xa5b\xe6\xceC\xea\xd0\x88\xebM\t\xd7\xf8\xc1*#hI\xd6F\x80\xb3B[\xa7\x99\x91\xbe\x16%Q\xf5\x1d(\xa0\x93\x87\n\x13\xbe\x92\x91\xcc\xbfT\x98b\xd3\x0b=\xc0\xd5\xb3\xdf}\xcc\xc9\xb1\xe4\'\xb1\xe25\xcc{tl\xe5\x92\xf34x\xd5\xa1\xf9K\xa4\xa8k\xa8 dU\xd7\x1e\xce\xb4\x02\xean\xc3\x10#\x05\x13L\x14\xa0(H\xd2d\xb8a\xbc\xdd\xee\x7f\x1b\xe5\xf1\xd2\xc5\x00\x00\x00'
And so when in python3 I'm receiving this error when I try to decode:
'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
The data received are not the same. The difference start after 'x12B#'. Someone has an explanation?
I'm not managing the server side so don't ask me to check this side!
Thanks,
Matthieu
For Python 3 you need to work with bytes, the data you have is not a text string so don't try and interpret it as one.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(15)
s.connect((SERVERIP, SERVERPORT))
s.send(message)
data = b''
while True:
new_data = s.recv(4096)
if not new_data:
break
data += new_data
s.close()
That should be all you need to receive the data: start with an empty bytes object created using b'' or just bytes(), but you will also have to be aware you are working with bytes when you come to process the data so that code will probably need changing as well.
You next step in processing this is probably:
import gzip
text = gzip.decompress(data)
and at this point it may be appropriate to change that to:
text = gzip.decompress(data).decode('ascii')
using whatever encoding is appropriate here (the sample data you posted above only contains ascii when decompressed so that might be all you need, or you might want utf-8 or some other encoding but you'll have to find out what was used to encode the data as you shouldn't attempt to guess). However it looks like it contains some pipe-separated fields so you might want to split the fields first and decode or otherwise process them individually:
fields = gzip.decompress(b).split(b'|')

Receiving data only if sent python socket

I am writing a messenger application in python and I have a problem. The problem is quite simple: I want the program to only receive data from the other computer if it was sent, otherwise, my program would wait for a data transfer infinitely. How would I write that piece of code? I imagine it'd be something like this:
try:
data = s.recv(1024).decode()
except:
data == None
See the select module. A socket can be monitored for readability with a timeout, so other process can proceed.
Example server:
import socket
import select
with socket.socket() as server:
server.bind(('',5000))
server.listen(3)
to_read = [server] # add server to list of readable sockets.
clients = {}
while True:
# check for a connection to the server or data ready from clients.
# readers will be empty on timeout.
readers,_,_ = select.select(to_read,[],[],0.5)
for reader in readers:
if reader is server:
client,address = reader.accept()
print('connected',address)
clients[client] = address # store address of client in dict
to_read.append(client) # add client to list of readable sockets
else:
# Simplified, really need a message protocol here.
# For example, could receive a partial UTF-8 encoded sequence.
data = reader.recv(1024)
if not data: # No data indicates disconnect
print('disconnected',clients[reader])
to_read.remove(reader) # remove from monitoring
del clients[reader] # remove from dict as well
else:
print(clients[reader],data.decode())
print('.',flush=True,end='')
A simple client, assuming your IP address is 1.2.3.4.
import socket
s = socket.socket()
s.connect(('1.2.3.4',5000))
s.sendall('hello'.encode())
s.close()

Resources