first of all thank you for your time. I have need to transfer images from one PC (Windows) to an other (Linux) and the other way arround. I used sockets and byte streams. How ever it takes 4 seconds to send one image which is insane amount of time. Am I missing some point here? Is there any library that supports fast file transfer on windows as well as on linux?
Server or sender
import numpy
import socket
import threading
import os
from idlelib.IOBinding import encoding
import Communication
import multiprocessing
import time
import cv2
import WrapDatastructures
import sys
import ImageProcessorClient
Queue = multiprocessing.Queue()
def SendFileToClient(name, sock, image, image_number):
#ImageRequest
ImageRequest = sock.recv(1024)
#Decode the Bytestring into ascii characters
ImageRequestAsStr = ImageRequest.decode('ascii')
print("Incoming Request String:",ImageRequestAsStr)
if ImageRequestAsStr == "FILEFLAG":
#Cascade to convert grayscale image to byte array and send it to Image Processor Client
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#Send size of the image to processor client
memoryConsumption = sys.getsizeof(gray_image)
print("Memory Consumtion",memoryConsumption)
sendStr = "EXISTS" + str(memoryConsumption)
#Convert the string to byte because otherwise it will not be send
sock.send((sendStr.encode(encoding)))
userResponse = sock.recv(1024)
#the Responce will be received in byte and will be converted to a string to make it checkable
userResponceStr = userResponse.decode('ascii')
if userResponceStr[:2] == 'OK':
#Get byte array
print("Convert grayscale_image to bytedata")
data = WrapDatastructures.singleChannelImgToByte(gray_image)
#bytesToSend = data #send 1024 bytes
#sock.send(bytesToSend)
sendData = 0
for i in range(0,memoryConsumption,1024):
sock.send(data[i:i+1024])
else:
print("User response not known")
else:
sendStr = "ERR"
sock.send(sendStr.encode(encoding))
sock.close()
def Main():
host = "127.0.0.1"
port = 5000
s = socket.socket()
s.bind((host,port))
s.listen(5)
#init camera
print("server started.")
imageCounterPerContainer = 0
while(True):
#Take image and put it in Q
#Call the controller to turn motor
#look for client to get request
if Queue.empty() is True:
#create client
print("create Client")
while True:
c, addr = s.accept()
print("client connected ip:< " + str(addr) +">")
imageCounterPerContainer +=1
t = threading.Thread(target = SendFileToClient, args=("rtrThread",c,cv2.imread("image_33.jpg"),imageCounterPerContainer))
t.start()
s.close()
if __name__ == "__main__":
Main()
Processor
import socket
from idlelib.IOBinding import encoding
import WrapDatastructures
import cv2
import time
def Main():
host = "127.0.0.1"
port = 5000
start = time.time()
s = socket.socket()
s.connect((host,port))
getfileRequest = "FILEFLAG"
if getfileRequest != "q":
s.send(getfileRequest.encode())
data = s.recv(1024)
dataStr = data.decode('ascii')
if dataStr[:6] == "EXISTS":
filesize = int(dataStr[6:])
print("Data is available size", filesize)
sendStr = "OK"
s.send(sendStr.encode(encoding))
#create new file new_filename and
img = b""
while True:
data = s.recv(1024)
if len(data) == 0:
break
img = b"".join([img, data])
print("Download Complete")
transferedImg = WrapDatastructures.ByteToCV2(img, (2048,2448))
cv2.imshow("transfered",transferedImg)
end = time.time()
print("Duration",end -start)
cv2.waitKey(0)
s.close()
else:
print("File does not exists")#
s.close()
s.close()
if __name__ == "__main__":
Main()
Related
I am trying to write a bit of code to create a 2 person live chat application using Python 3. The code is working in the sense of having live audio and live video, (as tested by running the server and 2 clients on the same device), with the Client-Side code running most of the logic and running the camera and audio feeds to send through the server, (which also works as a form of handshake between the 2 clients with little logic aside from if a client sends video and/or audio to send it to the other client), to have the client-side code to get the audio and video to play.
fair warning, this code is a bit messy and is not optimized for fast performance
Client-Side Code:
import cv2
from socket import socket, AF_INET, SOCK_STREAM
from imutils.video import WebcamVideoStream
import pyaudio
from array import array
from threading import Thread
import numpy as np
import zlib
import struct
HOST = input("Enter Server IP\n")
PORT_VIDEO = 3000
PORT_AUDIO = 4000
BufferSize = 4096
CHUNK=1024
lnF = 640*480*3
FORMAT=pyaudio.paInt16
CHANNELS=2
RATE=44100
def SendAudio():
while True:
data = stream.read(CHUNK)
dataChunk = array('h', data)
vol = max(dataChunk)
clientAudioSocket.sendall(data)
def RecieveAudio():
while True:
data = recvallAudio(BufferSize)
stream.write(data)
def recvallAudio(size):
databytes = b''
while len(databytes) != size:
to_read = size - len(databytes)
if to_read > (4 * CHUNK):
databytes += clientAudioSocket.recv(4 * CHUNK)
else:
databytes += clientAudioSocket.recv(to_read)
return databytes
def SendFrame():
while True:
try:
frame = wvs.read()
cv2_im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2.resize(frame, (640, 480))
frame = np.array(frame, dtype = np.uint8).reshape(1, lnF)
jpg_as_text = bytearray(frame)
databytes = zlib.compress(jpg_as_text, 9)
length = struct.pack('!I', len(databytes))
bytesToBeSend = b''
clientVideoSocket.sendall(length)
while len(databytes) > 0:
if (5000 * CHUNK) <= len(databytes):
bytesToBeSend = databytes[:(5000 * CHUNK)]
databytes = databytes[(5000 * CHUNK):]
clientVideoSocket.sendall(bytesToBeSend)
else:
bytesToBeSend = databytes
clientVideoSocket.sendall(bytesToBeSend)
databytes = b''
# ~ print("##### Data Sent!! #####")
except:
continue
def RecieveFrame():
while True:
try:
lengthbuf = recvallVideo(4)
length, = struct.unpack('!I', lengthbuf)
databytes = recvallVideo(length)
img = zlib.decompress(databytes)
if len(databytes) == length:
# ~ print("Recieving Media..")
# ~ print("Image Frame Size:- {}".format(len(img)))
img = np.array(list(img))
img = np.array(img, dtype = np.uint8).reshape(480, 640, 3)
cv2.imshow("Stream", img)
if cv2.waitKey(1) == 27:
cv2.destroyAllWindows()
else:
print("Data CORRUPTED")
except:
continue
def recvallVideo(size):
databytes = b''
while len(databytes) != size:
to_read = size - len(databytes)
if to_read > (5000 * CHUNK):
databytes += clientVideoSocket.recv(5000 * CHUNK)
else:
databytes += clientVideoSocket.recv(to_read)
return databytes
clientVideoSocket = socket(family=AF_INET, type=SOCK_STREAM)
clientVideoSocket.connect((HOST, PORT_VIDEO))
wvs = WebcamVideoStream(0).start()
clientAudioSocket = socket(family=AF_INET, type=SOCK_STREAM)
clientAudioSocket.connect((HOST, PORT_AUDIO))
audio=pyaudio.PyAudio()
stream=audio.open(format=FORMAT,channels=CHANNELS, rate=RATE, input=True, output = True,frames_per_buffer=CHUNK)
initiation = clientVideoSocket.recv(5).decode()
if initiation == "start":
SendFrameThread = Thread(target=SendFrame).start()
SendAudioThread = Thread(target=SendAudio).start()
RecieveFrameThread = Thread(target=RecieveFrame).start()
RecieveAudioThread = Thread(target=RecieveAudio).start()
Server-Side Code:
from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
import struct
HOST = input("Enter Host IP\n")
PORT_VIDEO = 3000
PORT_AUDIO = 4000
lnF = 640*480*3
CHUNK = 1024
BufferSize = 4096
addressesAudio = {}
addresses = {}
threads = {}
def ConnectionsVideo():
while True:
try:
clientVideo, addr = serverVideo.accept()
print("{} is connected!!".format(addr))
addresses[clientVideo] = addr
if len(addresses) > 1:
for sockets in addresses:
if sockets not in threads:
threads[sockets] = True
sockets.send(("start").encode())
Thread(target=ClientConnectionVideo, args=(sockets, )).start()
else:
continue
except:
continue
def ConnectionsSound():
while True:
try:
clientAudio, addr = serverAudio.accept()
print("{} is connected!!".format(addr))
addressesAudio[clientAudio] = addr
Thread(target=ClientConnectionSound, args=(clientAudio, )).start()
except:
continue
def ClientConnectionVideo(clientVideo):
while True:
try:
lengthbuf = recvall(clientVideo, 4)
length, = struct.unpack('!I', lengthbuf)
recvall(clientVideo, length)
except:
continue
def ClientConnectionSound(clientAudio):
while True:
try:
data = clientAudio.recv(BufferSize)
broadcastSound(clientAudio, data)
except:
continue
def recvall(clientVideo, BufferSize):
databytes = b''
i = 0
while i != BufferSize:
to_read = BufferSize - i
if to_read > (1000 * CHUNK):
databytes = clientVideo.recv(1000 * CHUNK)
i += len(databytes)
broadcastVideo(clientVideo, databytes)
else:
if BufferSize == 4:
databytes += clientVideo.recv(to_read)
else:
databytes = clientVideo.recv(to_read)
i += len(databytes)
if BufferSize != 4:
broadcastVideo(clientVideo, databytes)
# ~ print("YES!!!!!!!!!" if i == BufferSize else "NO!!!!!!!!!!!!")
if BufferSize == 4:
broadcastVideo(clientVideo, databytes)
return databytes
def broadcastVideo(clientSocket, data_to_be_sent):
for clientVideo in addresses:
if clientVideo != clientSocket:
clientVideo.sendall(data_to_be_sent)
def broadcastSound(clientSocket, data_to_be_sent):
for clientAudio in addressesAudio:
if clientAudio != clientSocket:
clientAudio.sendall(data_to_be_sent)
serverVideo = socket(family=AF_INET, type=SOCK_STREAM)
try:
serverVideo.bind((HOST, PORT_VIDEO))
except OSError:
print("Server Busy")
serverAudio = socket(family=AF_INET, type=SOCK_STREAM)
try:
serverAudio.bind((HOST, PORT_AUDIO))
except OSError:
print("Server Busy")
serverAudio.listen(2)
print("Waiting for audio connection..")
AcceptThreadAudio = Thread(target=ConnectionsSound)
AcceptThreadAudio.start()
serverVideo.listen(2)
print("Waiting for video connection..")
AcceptThreadVideo = Thread(target=ConnectionsVideo)
AcceptThreadVideo.start()
AcceptThreadVideo.join()
serverVideo.close()
Both of these codes are what I have put together in a bit longer of time than I would have liked, but I noticed when doing a bit of testing with these codes that the audio and video were off by anywhere between 3 and 7 seconds. I tried a bit of troubleshooting but couldn't find any issues with the code, aside from the fact that it looks like a kid threw it all together. I am fine with importing a new Python package, but I would prefer to use the Python Packages that I already have in place. Keep in mind I am thinking about eventually converting both the codes into separate .exe files to allow for easy access to send the codes to individual people.
I'm currently working on a project and I need to send a photo to another computer through Python. I'm using the module Socket but when I tried to send my photo, I got an error saying "A message sent to a datagram socket was larger than the internal message buffer or another network boundary, or the buffer used to receive a datagram was smaller than the datagram itself"
How can I fix that ?
Thanks
Your image is too big to be sent in one UDP packet. You need to split the image data into several packets that are sent individually.
socket.SOCK_STREAM instead of socket.SOCK_DGRAM. There you don't have to worry about packet sizes and ordering. Although you need to set buffer_size.
import random
import socket, select
from time import gmtime, strftime
from random import randint
imgcounter = 1
basename = "image%s.png"
HOST = '127.0.0.1'
PORT = 6666
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
buffer_size = 4096
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
print ' Buffer size is %s' % buffer_size
data = sock.recv(buffer_size)
txt = str(data)
if txt.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])
print 'got size'
print 'size is %s' % size
sock.send("GOT SIZE")
# Now set the buffer size for the image
buffer_size = 40960000
elif txt.startswith('BYE'):
sock.shutdown()
elif data:
myfile = open(basename % imgcounter, 'wb')
# data = sock.recv(buffer_size)
if not data:
myfile.close()
break
myfile.write(data)
myfile.close()
sock.send("GOT IMAGE")
buffer_size = 4096
sock.shutdown()
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
imgcounter += 1
server_socket.close()
Server code:
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 5005))
server_socket.listen(5)
import os
client_socket, address = server_socket.accept()
print "Conencted to - ",address,"\n"
while (1):
choice = client_socket.recv(1024)
choice = int(choice)
if(choice == 1):
data = client_socket.recv(1024)
print "The following data was received - ",data
print "Opening file - ",data
fp = open(data,'rb')
strng = fp.read()
size = os.path.getsize(data)
size = str(size)
client_socket.send(size)
client_socket.send (strng)
#client_socket.close()
if (choice == 2 or choice == 3):
data = client_socket.recv(1024)
print "The following data was received - ",data
print "Opening file - ",data
img = open(data,'rb')
while True:
strng = img.read(512)
if not strng:
break
client_socket.send(strng)
img.close()
print "Data sent successfully"
exit()
Client Code:
Please refer to https://docs.python.org/2/library/socket.html#socket.socket.setblocking
This code will be paused until it receives data. As default all sockets are in blocking mode. You should make it non-blocking.
In non-blocking mode, if a recv() call doesn’t find any data, or if a
send() call can’t immediately dispose of the data, an error exception
is raised; in blocking mode, the calls block until they can proceed.
s.setblocking(0) is equivalent to s.settimeout(0.0); s.setblocking(1)
is equivalent to s.settimeout(None).
Or:
put client_socket.settimeout(10.0) after while(1) and before client_socket.send(k)
write after while(1) -> c,a = client_socket.accept()
c.settimeout(10.0) -> then after that anywhere there is client_socket change it to "c"
Therefore:
client_socket.connect(("", 5005))
deadline = time.time() + 20.0
client_socket.settimeout(deadline - time.time())
#or
client_socket.setblocking(0)
All Code:
import socket,os
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("", 5005))
client_socket.settimeout(1.0)
k = ' '
size = 1024
while(1):
print "Do you want to transfer a \n1.Text File\n2.Image\n3.Video\n"
k = raw_input()
client_socket.send(k)
k = int (k)
if(k == 1):
print "Enter file name\n"
strng = raw_input()
client_socket.send(strng)
size = client_socket.recv(1024)
size = int(size)
print "The file size is - ",size," bytes"
size = size*2
strng = client_socket.recv(size)
print "\nThe contents of that file - "
print strng
if (k==2 or k==3):
print "Enter file name of the image with extentsion (example: filename.jpg,filename.png or if a video file then filename.mpg etc) - "
fname = raw_input()
client_socket.send(fname)
fname = 'documents/'+fname
fp = open(fname,'w')
while True:
try:
strng = client_socket.recv(512)
if not strng:
break
except timeout:
continue
fp.write(strng)
fp.close()
print "Data Received successfully"
exit()
I've written a code which is supposed to receive some images and make them black & white. I'm measuring the response time for each task (response time = the time each image is received and is turned to black & white). Here is the code:
from __future__ import print_function
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
from select import select
import socket
from struct import pack
from struct import unpack
#from collections import deque
import commands
from PIL import Image
import time
host = commands.getoutput("hostname -I")
port = 5005
backlog = 5
BUFSIZE = 4096
queueList = []
start = []
end = []
temp = []
def processP(q):
i = 0
while q:
name = q.pop(0)
col = Image.open(name)
gray = col.convert('L')
bw = gray.point(lambda x: 0 if x<128 else 255, '1')
bw.save("%d+30.jpg" % (i+1))
end.append(time.time())
#print(temp)
i = i + 1
class Receiver:
''' Buffer binary data from socket conn '''
def __init__(self, conn):
self.conn = conn
self.buff = bytearray()
def get(self, size):
''' Get size bytes from the buffer, reading
from conn when necessary
'''
while len(self.buff) < size:
data = self.conn.recv(BUFSIZE)
if not data:
break
self.buff.extend(data)
# Extract the desired bytes
result = self.buff[:size]
# and remove them from the buffer
del self.buff[:size]
return bytes(result)
def save(self, fname):
''' Save the remaining bytes to file fname '''
with open(fname, 'wb') as f:
if self.buff:
f.write(bytes(self.buff))
while True:
data = self.conn.recv(BUFSIZE)
if not data:
break
f.write(data)
def read_tcp(s):
conn, addr = s.accept()
print('Connected with', *addr)
# Create a buffer for this connection
receiver = Receiver(conn)
# Get the length of the file name
name_size = unpack('B', receiver.get(1))[0]
name = receiver.get(name_size).decode()
# Save the file
receiver.save(name)
conn.close()
print('saved\n')
queueList.append(name)
print('name', name)
start.append(time.time())
if (name == "sample.jpg"):
print('------------ok-------------')
processP(queueList)
print("Start: ", start)
print('--------------------------')
print("End: ", end)
while start:
temp.append(end.pop(0) - start.pop(0))
print('****************************')
print("Start: ", start)
print('--------------------------')
print("End: ", end)
print("Temp: ", temp)
i = 0
while i < len(temp)-1:
if (temp[i]<temp[i+1]):
print('yes')
else:
print('No')
i = i + 1
def read_udp(s):
data,addr = s.recvfrom(1024)
print("received message:", data)
def run():
# create tcp socket
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
tcp.bind((host,port))
except socket.error as err:
print('Bind failed', err)
return
tcp.listen(1)
# create udp socket
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
udp.bind((host,port))
print('***Socket now listening at***:', host, port)
input = [tcp,udp]
try:
while True:
inputready,outputready,exceptready = select(input,[],[])
for s in inputready:
if s == tcp:
read_tcp(s)
elif s == udp:
read_udp(s)
else:
print("unknown socket:", s)
# Hit Break / Ctrl-C to exit
except KeyboardInterrupt:
print('\nClosing')
raise
tcp.close()
udp.close()
if __name__ == '__main__':
run()
Now for some evaluation purposes, I send a single image many times. When I look at the response times I see that sometimes the response time of the 8th image, for example, is more than the response time of the 9th one.
So my question is that since the size and the time needed for processing each of images are the same (I'm sending a single image several times), Why is the response time for each image variable? Shouldn't the response time of the next image be longer (or at least equal) that the previous one (For example, the response time for 4th image > the response time for 3rd image)?
Your list contains the actual elapsed time it took for each image processing call. This value will be influenced by many things, including the amount of load on the system at that time.
When your program is running, it does not have exclusive access to all of the resources (cpu, ram, disk) of the system it's running on. There could be dozens, hundreds or thousands of other processes being managed by the OS vying for resources. Given this, it is highly unlikely that you would ever see even the same image processed in the exact same amount of time between two runs, when you are measuring with sub-second accuracy. The amount of time it takes can (and will) go up and down with each successive call.
Hello I got a problem with a type error I cant get rid off.
I have build a server named processA.py and a client processB.py
I start the server calling processA and it starts up
I start the client calling processB and it starts up
Now I input the name of the file I want to send over a socket.
The image must be in the same folder as the programms.
You can use the sample code from below for reproducing the error.
I choose: lena.jpg
I get an error in line 15, in of my processA.py:
sock.send("EXISTS" + str(os.path.getsize(filenameByte))) TypeError: a
bytes-like object is required, not 'str'
processA.py
'''
Created on 29 Nov 2017
#author: Poor Student
'''
import numpy
import socket
import threading
import os
def RtrFile(name, sock):
filenameByte = sock.recv(1024)
filenameStr = filenameByte.decode('ascii')
if os.path.isfile(filenameStr):
sock.send("EXISTS" + str(os.path.getsize(filenameByte)))
userResponse = sock.recv(1024)
if userResponse[:2] == 'OK':
with open(filenameByte, 'rb') as f:
bytesToSend = f.read(1024)
sock.send(bytesToSend)
while bytesToSend != "":
bytesToSend = f.read(1024)
sock.send(bytesToSend)
else:
sock.send("ERR")
sock.close()
def Main():
host = "127.0.0.1"
port = 5000
s = socket.socket()
s.bind((host,port))
s.listen(5)
print("server started.")
while True:
c, addr =s.accept()
print("client connected ip:< " + str(addr) +">")
t = threading.Thread(target = RtrFile, args=("rtrThread",c))
t.start()
s.close()
if __name__ == "__main__":
Main()
processB.py
'''
Created on 29 Nov 2017
#author: Poor Student
'''
import socket
def Main():
host = "127.0.0.1"
port = 5000
s = socket.socket()
s.connect((host,port))
filename = input("Filename? -> ")
if filename != "q":
s.send(filename.encode())
data = s.recv(1024)
if data[:6] == "EXISTS":
filesize = int(data[6:])
message = input("File Exists, " +str(filesize) + "Bytes, download? (Y/N)? ->")
if message == "Y" or message =="y":
s.send("OK")
f = open("new_" + filename, "wb")
data = s.recv(1024)
totalRecv = len(data)
f.write(data)
while totalRecv < filesize:
data = s.recv(1024)
totalRecv += len(data)
f.write(data)
print("(0:.f)".format((totalRecv)/float(filesize))*100 +"done")
print("Download Complete")
else:
print("File does not exists")#
s.close()
if __name__ == "__main__":
Main()
I found an answer. In python 3 you have allways convert your Strings to byte strings when sending them. After sending them to the receiver you have to decode them again and this must be done for the hole communication which is why the error allways shows up in the same module.
Process A:
'''
Created on 29 Nov 2017
#author: Happy student
'''
import numpy
import socket
import threading
import os
from idlelib.IOBinding import encoding
def RtrFile(name, sock):
filenameByte = sock.recv(1024)
filenameStr = filenameByte.decode('ascii')
print("FilenameStr",filenameStr)
if os.path.isfile(filenameStr):
print("Type:",type(filenameByte))
print(os.path.getsize(filenameByte))#
sendStr = "EXISTS" + str(os.path.getsize(filenameByte))
#Convert the string to byte because otherwise it will not be send
sock.send((sendStr.encode(encoding)))
userResponse = sock.recv(1024)
#the Responce will be received in byte and will be converted to a string to make it checkable
userResponceStr = userResponse.decode('ascii')
if userResponceStr[:2] == 'OK':
with open(filenameByte, 'rb') as f:
bytesToSend = f.read(1024)
sock.send(bytesToSend)
while bytesToSend != "":
bytesToSend = f.read(1024)
sock.send(bytesToSend)
else:
print("User response not known")
else:
sendStr = "ERR"
sock.send(sendStr.encode(encoding))
sock.close()
def Main():
host = "127.0.0.1"
port = 5000
s = socket.socket()
s.bind((host,port))
s.listen(5)
print("server started.")
while True:
c, addr =s.accept()
print("client connected ip:< " + str(addr) +">")
t = threading.Thread(target = RtrFile, args=("rtrThread",c))
t.start()
s.close()
if __name__ == "__main__":
Main()
processB.py
'''
Created on 29 Nov 2017
#author: Happy student
'''
import socket
from idlelib.IOBinding import encoding
def Main():
host = "127.0.0.1"
port = 5000
s = socket.socket()
s.connect((host,port))
filename = input("Filename? -> ")
if filename != "q":
s.send(filename.encode())
data = s.recv(1024)
dataStr = data.decode('ascii')
if dataStr[:6] == "EXISTS":
filesize = int(dataStr[6:])
message = input("File Exists, " +str(filesize) + "Bytes, download? (Y/N)? ->")
if message == "Y" or message =="y":
sendStr = "OK"
s.send(sendStr.encode(encoding))
#create new file new_filename and
f = open("new_" + filename, "wb")
data = s.recv(1024)
totalRecv = len(data)
f.write(data)
while totalRecv < filesize:
data = s.recv(1024)
totalRecv += len(data)
f.write(data)
print("Download Complete")
else:
print(message +"was not noticed")
exit()
else:
print("File does not exists")#
s.close()
if __name__ == "__main__":
Main()
Recently I wrote some code (client and server) to send an image - the client simply uploads the image to the server, just using the socket module: Sending image over sockets (ONLY) in Python, image can not be open.
However, the image sending part is now what I am concerned with. This is the original image I'm using:
In my server code (which receives the images), I have these lines:
myfile = open(basename % imgcounter, 'wb')
myfile.write(data)
data = sock.recv(40960000)
if not data:
myfile.close()
break
myfile.write(data)
myfile.close()
sock.sendall("GOT IMAGE")
sock.shutdown()
But I don't think this is the best way of doing it. I think I should instead implement the server such that it receives the data in chunks:
#!/usr/bin/env python
import random
import socket, select
from time import gmtime, strftime
from random import randint
imgcounter = 1
basename = "image%s.png"
HOST = '127.0.0.1'
PORT = 2905
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
data = sock.recv(4096)
txt = str(data)
if data:
if data.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])
print 'got size %s' % size
sock.sendall("GOT SIZE")
elif data.startswith('BYE'):
sock.shutdown()
else :
myfile = open(basename % imgcounter, 'wb')
myfile.write(data)
amount_received = 0
while amount_received < size:
data = sock.recv(4096)
amount_received += len(data)
print amount_received
if not data:
break
myfile.write(data)
myfile.close()
sock.sendall("GOT IMAGE")
sock.shutdown()
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
imgcounter += 1
server_socket.close()
But when I do this, the server prints:
got size 54674
4096
8192
12288
16384
20480
24576
28672
32768
36864
40960
45056
49152
50578
And then seems to hang, and the client hangs too. However, at the server's side I can see only a piece of the image the client wanted to send:
It seems like there are some bytes missing. What is the proper way of sending a huge amount of data (images, other type of file) using ONLY sockets?
I'm assuming that you have a particular reason for doing this with naked sockets, such as self-edification, which means that I won't answer by saying "You accidentally forgot to just use HTTP and Twisted", which perhaps you've heard before :-P. But really you should look at higher-level libraries at some point as they're a lot easier!
Define a protocol
If all you want is to send an image, then it can be simple:
Client -> server: 8 bytes: big endian, length of image.
Client -> server: length bytes: all image data.
(Client <- server: 1 byte, value 0: indicate transmission received - optional step you may not care if you're using TCP and just assume that it's reliable.)
Code it
server.py
import os
from socket import *
from struct import unpack
class ServerProtocol:
def __init__(self):
self.socket = None
self.output_dir = '.'
self.file_num = 1
def listen(self, server_ip, server_port):
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.bind((server_ip, server_port))
self.socket.listen(1)
def handle_images(self):
try:
while True:
(connection, addr) = self.socket.accept()
try:
bs = connection.recv(8)
(length,) = unpack('>Q', bs)
data = b''
while len(data) < length:
# doing it in batches is generally better than trying
# to do it all in one go, so I believe.
to_read = length - len(data)
data += connection.recv(
4096 if to_read > 4096 else to_read)
# send our 0 ack
assert len(b'\00') == 1
connection.sendall(b'\00')
finally:
connection.shutdown(SHUT_WR)
connection.close()
with open(os.path.join(
self.output_dir, '%06d.jpg' % self.file_num), 'w'
) as fp:
fp.write(data)
self.file_num += 1
finally:
self.close()
def close(self):
self.socket.close()
self.socket = None
# could handle a bad ack here, but we'll assume it's fine.
if __name__ == '__main__':
sp = ServerProtocol()
sp.listen('127.0.0.1', 55555)
sp.handle_images()
client.py
from socket import *
from struct import pack
class ClientProtocol:
def __init__(self):
self.socket = None
def connect(self, server_ip, server_port):
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect((server_ip, server_port))
def close(self):
self.socket.shutdown(SHUT_WR)
self.socket.close()
self.socket = None
def send_image(self, image_data):
# use struct to make sure we have a consistent endianness on the length
length = pack('>Q', len(image_data))
# sendall to make sure it blocks if there's back-pressure on the socket
self.socket.sendall(length)
self.socket.sendall(image_data)
ack = self.socket.recv(1)
# could handle a bad ack here, but we'll assume it's fine.
if __name__ == '__main__':
cp = ClientProtocol()
image_data = None
with open('IMG_0077.jpg', 'r') as fp:
image_data = fp.read()
assert(len(image_data))
cp.connect('127.0.0.1', 55555)
cp.send_image(image_data)
cp.close()
A simple way is to send data size as the first 4 bytes of your data and then read complete data in one shot. Use the below functions on both client and server-side to send and receive data.
def send_data(conn, data):
serialized_data = pickle.dumps(data)
conn.sendall(struct.pack('>I', len(serialized_data)))
conn.sendall(serialized_data)
def receive_data(conn):
data_size = struct.unpack('>I', conn.recv(4))[0]
received_payload = b""
reamining_payload_size = data_size
while reamining_payload_size != 0:
received_payload += conn.recv(reamining_payload_size)
reamining_payload_size = data_size - len(received_payload)
data = pickle.loads(received_payload)
return data
you could find sample program at https://github.com/vijendra1125/Python-Socket-Programming.git
The problem is you are not incrementing amount_received for the first chunk of the data received.
Fix below:
#!/usr/bin/env python
import random
import socket, select
from time import gmtime, strftime
from random import randint
imgcounter = 1
basename = "image%s.png"
HOST = '127.0.0.1'
PORT = 2905
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
data = sock.recv(4096)
txt = str(data)
if data:
if data.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])
print 'got size %s' % size
sock.sendall("GOT SIZE")
elif data.startswith('BYE'):
sock.shutdown()
else :
myfile = open(basename % imgcounter, 'wb')
myfile.write(data)
amount_received = len(data) # The fix!
while amount_received < size:
data = sock.recv(4096)
amount_received += len(data)
print amount_received
if not data:
break
myfile.write(data)
myfile.close()
sock.sendall("GOT IMAGE")
sock.shutdown()
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
imgcounter += 1
server_socket.close()