views:

2391

answers:

3

Let's say I want to read a line from a socket, using the standard socket module:

def read_line(s):
    ret = ''

    while True:
        c = s.recv(1)

        if c == '\n' or c == '':
            break
        else:
            ret += c

    return ret

What exactly happens in s.recv(1)? Will it issue a system call each time? I guess I should add some buffering, anyway:

For best match with hardware and network realities, the value of bufsize should be a relatively small power of 2, for example, 4096.

http://docs.python.org/library/socket.html#socket.socket.recv

But it doesn't seem easy to write efficient and thread-safe buffering. What if I use file.readline()?

# does this work well, is it efficiently buffered?
s.makefile().readline()
+6  A: 

The recv() call is handled directly by calling the C library function.

It will block waiting for the socket to have data. In reality it will just let the recv() system call block.

file.readline() is an efficient buffered implementation. It is not threadsafe, because it presumes it's the only one reading the file. (For example by buffering upcoming input.)

If you are using the file object, every time read() is called with a positive argument, the underlying code will recv() only the amount of data requested, unless it's already buffered.

It would be buffered if:

  • you had called readline(), which reads a full buffer

  • the end of the line was before the end of the buffer

Thus leaving data in the buffer. Otherwise the buffer is generally not overfilled.

The goal of the question is not clear. if you need to see if data is available before reading, you can select() or set the socket to nonblocking mode with s.setblocking(False). Then, reads will return empty, rather than blocking, if there is no waiting data.

Are you reading one file or socket with multiple threads? I would put a single worker on reading the socket and feeding received items into a queue for handling by other threads.

Suggest consulting Python Socket Module source and C Source that makes the system calls.

Joe Koberg
I don't really know why I asked about thread-safety, I don't need it in my current project. In fact I want to rewrite a Java program in Python. In Java it's easy to get buffered reading, and I was wondering if Python's socket module provides the same buffering (in fact, I wonder why someone wouldn't want buffering and directly call system calls instead).
Bastien Léonard
+1  A: 

If you are concerned with performance and control the socket completely (you are not passing it into a library for example) then try implementing your own buffering in Python -- Python string.find and string.split and such can be amazingly fast.

def linesplit(socket):
    # untested
    buffer = socket.read(4096) # thx!
    done = False
    while not done:
        if "\n" in buffer:
            (line, buffer) = buffer.split("\n", 1)
            yield line+"\n"
        else:
            more = socket.read(4048)
            if not more:
                done = True
            else:
                buffer = buffer+more
    if buffer:
        yield buffer

If you expect the payload to consist of lines that are not too huge, that should run pretty fast, and avoid jumping through too many layers of function calls unnecessarily. I'd be interesting in knowing how this compares to file.readline() or using socket.recv(1).

Aaron Watters
4048 is a rather odd buffer size. You should stick to powers of 2.
Christian Witts
A: 

I am trying to achieve a similar thing in Python for S60 (symbian), running a .recv on a socket object without it freezing my UI. I have tried the setblocking(False) method to prevent this function from blocking the main app, however it has not worked for me. (tested on both the socket instance and the connection instance from socket.accept() )

Have also attempted using select() to create a non-blocking function, however have also had no success with this method.

My application does not require separate threads, however I just want to be able to access the UI while this function is running.

Any help would be appreciated.. Sorry for crashing your question, but hopefully I can contribute some tests and results?

I think you would get more help if you posted a new question. About your problem, I guess threads are the way to go if had no success with select(). Or maybe you could find a library which manages that.
Bastien Léonard