2

I am making an iPhone application that communicates to a Twisted socket and it works great when I have one message to send. However, my issue is I need to send many different bits of information to the app. Here is my code.

            if numrows == 1:
                #Did login
                msg = "%s: Login Credentials Success" % _UDID
                print msg
                for c in self.factory.clients:
                    c.message(msg)
                    time.sleep(0.5)

                for result in results:
                    for i in range(1, 6):
                        msg = "%s:L%d;%s" % (_UDID, i, result[i])
                        print msg
                        for c in self.factory.clients:
                            c.message(msg)
                            time.sleep(0.5)
            else:
                msg = "%s: Login Credentials Failed" % _UDID
                print msg
                for c in self.factory.clients:
                    c.message(msg)
                    time.sleep(0.5)

            cursor.close()
            database.close()

        #print msg

        #for c in self.factory.clients:
            #c.message(msg)

def message(self, message):
    self.transport.write(message)

Say I were to send just the first msg, and every other msg didn't exist along with the print and for methods below each msg, the message Login Credentials Success would be sent to the app. But if put in the rest like how you are seeing it, nothing goes though because it sends it all at once, even with putting a time.sleep in the code.

The app checks the response every .05 seconds or less. Even though that the login credentials is on the top, it doesn't go through because there is more info that is being sent afterwards, but without all the info after the credentials message, it would go through.

I am desperate in finding the answer to this. I've tried everything I can think of. The app is not the issue, it's the Python.

Thanks.

Alec
  • 919
  • 2
  • 10
  • 25

2 Answers2

2

At a risk of offending by contradicting, you may want to reexamine the claim that your app is not the problem. It sounds like you are expecting to have complete control over the content of each outgoing TCP packet, and that your app is depending on packet boundaries to determine the message boundaries. This isn't a very good approach to networking in general; some network intermediaries may split up (fragment) or even combine packets along the way, which would confuse your app. Remember that TCP is not a packet protocol: it is a stream protocol, so you're only really guaranteed that the octets you sent will be received in order, if at all.

A common approach to dealing with messages of varying size is to prefix each message with an X-bit big-endian size field stating how large the following message is. The receiving end of the communication reads X bits first, then reads 'size' octets after that to get the full message (blocking until that point, and leaving any additional information in the buffer for the next message handler to get).

I wouldn't mind helping more with your Twisted code, but it may very well be that it's already written properly. At least, I recommend not depending on trying to make Twisted flush network write buffers immediately. While it may help make your code appear to work right, right now, it will really just be hiding problems that will surface later.

the paul
  • 8,972
  • 1
  • 36
  • 53
  • Thanks for not minding to help me. Maybe it is my app, but I feel so strongly that it is my Python. If you would be able to help me, thanks paul. – Alec May 22 '12 at 02:11
  • Is there a specific problem you're still having, after having read and understood the above? – the paul May 22 '12 at 16:53
  • The problem is if I send a message that starts with say "login:", the app would read it. However if I go in the for loops and do login: then the for loop containing more info, the app doesn't show any response. I think it may be just printing and not sending a message at all. – Alec May 22 '12 at 22:38
  • I'm not clear on exactly what you mean by "do login:", or the "for loop containing more info". Maybe it would help to post some (simplified) code for the other end of your app? – the paul May 23 '12 at 04:56
  • I can't get to the python or app because it is in another city on another computer of mine. The socket sends "Login:UDID_HERE;Sucessful" to the app to show the login was successful. It works correctly, but when I add other things to send (such as the for loop) it doesn't send, even with the time sleep. I can get you the code this weekend somehow. – Alec May 23 '12 at 20:04
  • My problem is that I send a message to the server and then I'm done. I want to exit my application. But if I do - nothing is sent!?! The solution: flush out going buffers before exiting application. I have no been able to find how for a whole day now :(. – Carlo Wood Apr 18 '20 at 19:08
  • @CarloWood you might want to make that its own toplevel question. But in short, see the [Why does it take a long time for data I send with transport.write to arrive at the other side of the connection?](https://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#WhydoesittakealongtimefordataIsendwithtransport.writetoarriveattheothersideoftheconnection) FAQ. You might be able to get away with something like `reactor.callLater(0, reactor.stop)` which should add a callback to the reactor that shuts it down once it handles other pending tasks. – the paul Apr 24 '20 at 14:43
1

Your issue appears to be that Twisted buffers the data you write to it.

Apparently, there is no easy way to force the data to be sent on its own without refactoring a great deal of your code. See Twisted transport.write and Using Twisted's twisted.web classes, how do I flush my outgoing buffers?.

Without knowing what your code looks like before the snipped you pasted and, according to the accepted answer of the last link:

  • define the wait function just as it is in the accepted answer
  • make sure that your class inherits from http.Request
  • decorate your method message with defer.inlineCallbacks
  • add yield wait(N) (for a value of N that you have to test and determine) after calls to write on the message method

I don't have enough experience with Twisted to know which of those steps are needed and which are just curft from the code of the original answer that doesn't apply to your code.

It may be possible (and easier) though, to re-write the iPhone application to accept the kind of messages that get sent when they include multiple writes in a single message.

Community
  • 1
  • 1
Toote
  • 3,323
  • 2
  • 19
  • 25
  • I have checked both of those pages already, but I can't figure out what to code. I'm not strong in Python, so if you can help me with the code, it be much appreciated. – Alec May 20 '12 at 01:01
  • @AlecK. if you *"aren't strong in Python"* then Twisted is **not** the framework to be trying to use. It is complicated and hard to get correct even for those very experienced in Python. –  May 21 '12 at 19:23
  • This is quite a useful answer. Just a note, your class doesn't have to inherit from http.Request. The defining of the wait function, the decorator and the yield statements are whats necessary. – Arthur.V Sep 02 '15 at 12:45