Im having trouble with looping in my recv(). It seems that 2 out of every 3 times I run my program, the resulting image.jpg ends up “unfinished”. Is there supposed to be a better way of looping the data in? The looping in function is called from the prompt via “exec userInput”.
###########################################
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 12345
s.bind((host, port))
s.listen(1)
data = “”
def r():
global data
data += c.recv(int(1000000))
while data == True:
try:
data += c.recv(int(1000000))
except: break
First off, please wrap your code samples in the CODE tag so that the indents are preserved correctly.
Yes, there is a much better way to receive data. First that you should know that sockets are not guaranteed to be able to fully read or write the entire buffer in a single pass.
So if you do:
socket.send(buffer)
You have to check to see if the entire buffer was actually sent. i.e. The ‘send’ method returns the number of bytes that it was actually able to send. You then have to try to resend your buffer. You can do something like this:
# Assumes that 'buffer' is already loaded with data
numToSend = len(buffer) # Get total length that will be sent.
while numToSend > 0: # Keep trying to send data until it is all sent
numMoved = socket.send(buffer) # Send data and see how much actually went out.
buffer = buffer[numMoved:] # Remove that number of bytes from the buffer
numToSend -= numMoved # Update the total that needs to be sent
With a larger data like a JPG can be, it is very likely that you won’t get all you data out in a single send call.
That is the reason that your recv data is getting lost as well. ‘recv’ won’t block until all the data sent is received. What you usually do is first sent an int that tells how much data is going to come down the pipe. Then you ‘recv’ data until that amount have arrived, then you wait for another message indicating the start of a new message.
recvBuffer = socket.recv(4) # Read up to 4 bytes for an int.
numInImage = recvBuffer.asInt() # Pseudo-code, I forget how to change a byte array into an int.
# Remember how much data was in the imgBuffer on the last read
lastReadAmount = 0
# Loop until all the data is in.
while numInImage > 0:
# See how much to read in. Either try to get 4096 bytes or try to get the remaining data
numToRead = min(numInImage, 4096)
# Read the data
imgBuffer += socket.recv(numToRead)
# See how much data was read in this pass.
numInImage -= len(imgBuffer) - lastReadAmount
# Remember how much is currently in the buffer.
lastReadAmount = len(imgBuffer)
None of this code is tested to there might be bugs in there.
after hours of trial and error. I finally have a working prototype. I combined your answer with 2 other recources I found on the internet and i think i have it working pretty well. thanks kastoria for helping me become a better coder. Btw how do I empliment the code tags so that my code shows up right in the thread?