Sockets: Sending/receiving arbitrary amounts of data

Neil Schemenauer nas at python.ca
Tue May 1 16:55:08 EDT 2001


Cary O'Brien wrote:
> In article <mailman.988566942.26667.python-list at python.org>,
> Neil Schemenauer  <nas at python.ca> wrote:
> >    def write_string(s, sock):
> >        sock.send("%lu:" % len(s))
> >        sock.send(s)
> 
> Woops!  Are you *SURE* that the python send will retry in the face
> of short writes?  The docs say send returns the number of bytes
> sent, so you probably need to check the send return value, slice
> off what was sent, and try again.

Not sure.  My man page for send(2) seems to indicate that it does
unless the socket is in non-blocking mode.  I'll have to consult
Stevens when I get home.

> You gotta retry the recv() also if your data is bigger
> than the socket buffering.  But someone else pointed
> this out.

Right.  How about this:

    def _read_size(input):
        size = ""
        while 1:
            c = input.read(1)
            if c == ':':
                break
            elif not c:
                raise IOError, 'short netstring read'
            size = size + c
        return long(size)

    def write_string(s, output):
        output.write('%lu:' % len(s))
        output.write(s)
        output.write(',')

     def read_string(input):
        size = _read_size(input)
        data = ""
        while len(data) < size:
            s = input.read(size)
            if not s:
                raise IOError, 'short netstring read'
            data = data + s
        if input.read(1) != ',':
            raise IOError, 'missing netstring terminator'
        return data

    def write_file(input, output, blocksize=4096):
        size = os.fstat(input.fileno())[6]
        output.write("%lu:" % size)
        while 1:
            data = input.read(blocksize)
            if not data:
                break
            output.write(data)
        output.write(",")

    def read_file(input, output, blocksize=4096):
        size = _read_size(input)
        while size > 0:
            s = input.read(min(blocksize, size))
            if not s:
                raise IOError, 'short netstring read'
            output.write(s)
            size = size - len(s)
        if input.read(1) != ',':
            raise IOError, 'missing netstring terminator'


You have to use .makefile() on your sockets of course.

  Neil




More information about the Python-list mailing list