sending a file through sockets

Bryan Olson fakeaddress at nowhere.org
Thu Jul 4 21:56:00 EDT 2002


brueckd at tbye.com wrote:

 > Guyon Morée wrote:
 >>so the trick is to convert a file to a string representation right?

 > Um... you *could* do that, but it wouldn't actually help at all. The
 > contents of the file already are in a string representation because 
Python
 > strings can contain anything, including binary characters. The 
easiest way
 > to send a file is to simply read the data from the file and send it out
 > the socket,

Right.

 > but to send the length of the file first so the receiving end
 > knows if and when it got the whole thing.

That's not really needed.  Just  call shutdown(1) when finished writing.
The receiver can detect the end when recv() returns zero bytes without
error, which only happens on clean shutdown.  The socket will also
select() as readable just before the zero-byte recv().

The only snag is if a local error causes the sender to close the socket
before sending all the data.  Note that in the code, you don't actually
check that you've received as much data as expected.  The code uses the
size to know when to stop reading, and the "if not data: break" will do
that anyway.


 > If you need too much more
 > functionality than this it might be easier to just use one of the 
standard
 > file transfer protocols, e.g. FTP.

Good advice.  For most applications, I'd recommend the HTTP family.


 > Anyway, here's some sample code, but if
 > you're not already familiar with sockets then you should spend a little
 > time experimenting with them.

Did you test this?  The Python library uses the empty string for
INADDR_ANY, which is fine for bind(), but I don't think it's legal for
connect().

I understand it's a basic demo, but I'll note that any real application
requires some time-out discipline to avoid very long hangs.  Also on
most Unix systems we'd need to watch out for signals that force system
calls to return.


--Bryan


 > The sending side listens for incoming connections and sends out the 
file.
 > The receiving side connects to the "server" and writes the file to disk.
 >
 > Common code:
 > import struct
 > PORT = 5555
 > FILENAME = 'foo.bin'
 > HDR = '!I'
 > HDR_SZ = struct.calcsize(HDR)
 >
 > Sending side:
 > import os
 > from socket import *
 > s = socket(AF_INET,SOCK_STREAM)
 > s.bind(('',PORT))
 > s.listen(1)
 > while 1:
 >   q,v = s.accept()
 >   q.sendall(struct.pack(HDR, os.path.getsize(FILENAME)))
 >   f = open(FILENAME,'rb')
 >   while 1:
 >     data = f.read(4096)
 >     if not data: break
 >     q.sendall(data)
 >   q.close()
 >
 > Receiving side:
 > from socket import *
 > f = open(FILENAME, 'wb')
 > s = socket(AF_INET, SOCK_STREAM)
 > s.connect(('', PORT))
 > size = s.recv(HDR_SZ)
 > size = struct.unpack(HDR, size)
 > while size > 0:
 >   data = s.recv(4096)
 >   if not data: break
 >   size -= len(data)
 >   f.write(data)
 > s.close()







More information about the Python-list mailing list