0

I got some code to receive data that looks like this: (SSL being used)

sockListToCheck = self.getSocketList(self.clientSocketsWTTL)
        socksReady, w, e = select.select(sockListToCheck,[],[], d_consts.SELECT_SEC)

        if not socksReady: #list empty
            print 'not ready'
            return #nothing received yet so don't change anything

        leftInError = False
        #we have something
        for sock in socksReady:
            dataBuf = ""
            c1 = 5
            c2 = 5
            while True:
                try:
                    dat = sock.recv(d_consts.BUF_SIZE) # read what is there to read
                    dataBuf += dat
                    print(dat), len(dat)
                    if len(dat) < d_consts.BUF_SIZE and c1 == 0:
                        c1 -= 1
                        print 'about to break'
                        break
                except ssl.SSLError as e:
                    #print 'trying to read '
                    # Ignore the SSL equivalent of EWOULDBLOCK, but re-raise other errors
                    #print e
                    if e.errno != ssl.SSL_ERROR_WANT_READ:
                        print 'serious ssl error'
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close() #close
                        leftInError = True
                    else: 
                        if c2 == 0:
                            break
                        c2 -= 1
                        continue

            if (leftInError):
                leftInError = False
                print 'left error'
                continue

I am having problems when there are some significant delays, so I added those counters. My problem is that, if I don't know how big the message is, I don't know when to stop receiving. I used to break when the received amount was less than the buffer, but it appears that sometimes this happens anyway but not all the data has arrived. Are there any other ways? Maybe some timeout or something?

kirelagin
  • 13,248
  • 2
  • 42
  • 57
unixsnob
  • 1,685
  • 2
  • 19
  • 45

2 Answers2

1

That's a general problem of network programming. The answer is that in most cases you shouldn't be using raw sockets.

Normally I'd suggest switching to ØMQ as it's brilliant library ans it lets you work in terms of messages instead of TCP's stream of bytes. That's what you actually need most of the time.

But unfotunatelly ØMQ doesn't work well with SSL right now. So, you, naturally, have two options:

  1. Writing lots of boilerplate code. You'll need a wire protocol (with, at least, “message length” field) and code that will carefully read bytes from the socket, counting them.
  2. Using some existing library. The first thing that comes to my mind is using a message broker, for example, RabbitMQ, which supports SSL.
  3. A more radical solution (but I think the most awesome one) is getting rid of TCP altogether and moving to a more powerful protocol, e.g. SCTP. You probably shouldn't choose this option…

If you choose the first option.

First of all, vefore sending a message, send its length in some fixed-length format (e.g. 4-byte unisgned integer). And now:

  1. Create a buffer (list of bytes).
  2. Keep reading from socket and appending to this buffer until you've got 4 bytes.
  3. When length of your buffer is at least four, you strip first four bytes, and keep the rest:

    if len(buffer) >= 4:
        expected_length = int(buffer[:4])
        buffer = buffer[4:]
    
  4. Now you continue receiving bytes into the buffer until its length becomes expected_length.
  5. When len(buffer) >= expected_length you've got the message.

Something similar is shown in Python Sockets HOWTO but they assume fixed-length message.

Community
  • 1
  • 1
kirelagin
  • 13,248
  • 2
  • 42
  • 57
  • In an ideal world, I wouldn't. That is true. Unfortunate, this is a modification to already existing code for a prototype so I need to use it. Can you give me some examples on timeouts or something like that? like wait a second and if the message didn't arrive, abort? – unixsnob Jun 08 '13 at 10:21
  • @unixsnob no, timeouts are not a great idea. Ok, I'll extend my answer in a minute. – kirelagin Jun 08 '13 at 10:49
-1

It's difficult to say exactly what's wrong with your code because it's not complete (for example, the code that creates the sockets is missing, so I can't tell if they're blocking or non-blocking sockets or even some mix of the two). I also can't run the code and explore the misbehavior, which helps a whole lot in figuring things like this out.

However, I suggest using Twisted's SSL support instead. It will do all of this boring low-level stuff for you and let you concentrate on your actual application.

At the very worst, you can read Twisted's SSL implementation (or the old one) to learn all about the various corner cases you need to address to be able to use SSL and select together.

Jean-Paul Calderone
  • 47,755
  • 6
  • 94
  • 122