-1

I am writing a Ryu application(Python) in which I have if else statement. If a condition satisfies for the first time, then it should start the timer till 10 seconds, within these 10 seconds there will be other packets arriving as well matching the same condition but I don't want to start timer every time a condition is satisfied(within these 10 seconds). In short, the timer should run in parallel.

Here is the code snippet I used for thread. Every time I run this and send multiple packets then multiple threads start whereas I want only one thread to run till 10 seconds

def timeit():
         time.sleep(10)
         aggr()
         return

def aggr():
         self.no_of_data=len(self.iot_data)
         self.ip_proto=proto
         self.ip_saddr=source
         self.ip_daddr=destination
         ip_head= pack('!BBHHHBBH16s16s' , self.ip_ihl_ver, self.ip_tos, self.ip_tot_len, self.ip_id, self.ip_frag_off, self.ip_ttl,self.ip_check,self.ip_proto, self.ip_saddr, self.ip_daddr)
         total_pkts= pack('!I', self.no_of_data)
         print "TOTALLLL,,,,",self.no_of_data
         ip_head="{" + ip_head + "}"
         total_pkts="{" + total_pkts + "}"
         s='$'
         data = s.join(self.iot_data)
         data="$" + data
         pckt= ip_head + total_pkts + data
         self.iot_data = []
         print "BUFFER: ", self.iot_data
         self.iot_data_size = 0
         self.start_time = time.time()
         self.logger.info("packet-out %s" % (repr(pckt),))
         out_port = ofproto.OFPP_FLOOD
         actions = [parser.OFPActionOutput(out_port)]
         out = parser.OFPPacketOut(datapath=datapath,
               buffer_id=ofproto.OFP_NO_BUFFER,
               in_port=in_port, actions=actions,                                          
               data=pckt)
         print "out--->" , out
         datapath.send_msg(out)
thread1 = threading.Thread(target=timeit)
thread1.start()
if  proto  == 150 and total_len  < 1500:
        if not thread1.isAlive():
                thread1.run()
        print "ifff"
        data = msg.data
        #print " # stores the packet data"
        self.iot_data.append(data)
        #print "# increment size counter"
        self.iot_data_size += total_len
        #elapsed_time = time.time() - self.start_time
        print "ELAPSED: ", elapsed_time
        print "BUFFER: ", self.iot_data

After 10 seconds, again timer should start when the first packet arrives and it should run parallel with the same code. I am so much confused with this. Please anyone help.

I hope this is clear if not I am sorry please ask for the clarification.

Thank you

Trrrrrr
  • 5
  • 1
  • 8

1 Answers1

0

Indeed, you have to go with multi-threading (might be achieved without it but it would certainly be a pain in the ass). The idea is to run a thread that will run a function that sleeps for 10 seconds and returns. After this function returns, the thread will be set as inactive, until we run it the next time.

By knowing that we can write the following code. All details and explanations are written as comments for easier reference.

import time
import threading

packet_groups = [] # Groups of packets inside 10 seconds.
group = [] # Temporary group that will get stored into packet_groups.

# The function that will count 10 seconds:
def timeit():
    sleep(10)
    return

# Do something with packets.
def packet_handler():
    ...

# Put all your code inside another function that does not create
# new thread each time. Create a thread in main and then run this function.
def get_packets(thread1):
    ... # get packets
    if dst == 'some_address':
        # Check if thread is alive. If it is alive, a counter is running.
        # If it is not alive, then we must start the counter by running
        # thread.
        if not thread1.isAlive():
            thread1.run()
            packet_handler(packet, True)
        else:
            packet_handler(packet, False)

if __name__ == '__main__':
    # Create thread.
    thread1 = threading.Thread(target=timeit)
    # Start the thread. This is done only once per each thread.
    thread1.start()

    get_packets(thread1)

Now since you mentioned that you want to group the packets inside these 10 seconds blocks, you can implement packet_handler() like this:

def packet_handler(packet, new):
    # If we started new thread and the group isn't empty, we must
    # append group to packet_groups (that is all groups) and reset
    # the group to only contain current packet
    if new and group != []:
        packet_groups.append(group)
        group = [packet]
        return
    # If group isn't new, we are still inside 10 seconds block. We
    # just append the current packet to this block.
    if not new:
        group.append(packet)

If you want to be able to print or in any other way be able to show the timer, you can't sleep for 10 seconds because if you sleep for 10 seconds, nothing will be done in between. In such case you want to change timeit() to something like this:

def timeit():
    for i in range(10):
        print 'Time remaining: {0}s'.format(10-i)
        sleep(1)
    return
campovski
  • 2,979
  • 19
  • 38
  • Thanks @campovski for your quick answer. I need it because I am aggregating packets going to a specific destination for 10 seconds. I tried your code, I am getting error : 'TypeError: run() takes exactly 1 argument (2 given)'. – Trrrrrr Sep 04 '17 at 08:20
  • Thank you, @campovski Sir, It is working fine as I wanted :). Thanks for the expansion of code later though I already had packet aggregator code ready, I was only stuck with the timer. Another small question, Is there any way we can display the count down from sleep() method? like 10,9,8... – Trrrrrr Sep 04 '17 at 09:35
  • Wow, that was real quick. Thank you so much :) @campovski – Trrrrrr Sep 04 '17 at 09:46
  • No problemo, amigo :) if your problem was solved, consider marking the answer as accepted, so other people will know that the problem has been solved without needing to going through whole site. Also consider upvoting the answer if it was helpful. Just teaching you the nice SO policy ;) – campovski Sep 04 '17 at 09:51
  • No problem :D accepting an answer is crucial to keeping Q&As clean, not upvoting them – campovski Sep 04 '17 at 10:41
  • Hi @campovski, I just found that thread is running again and again when the condition is satisfied. Like when a packet arrives one thread started and then when another arrives then another thread starts :(. I don't know why is this case – Trrrrrr Sep 04 '17 at 10:55
  • I edit my code.. can you please check and point out what I am doing wrong? @campovski – Trrrrrr Sep 04 '17 at 14:20
  • The packets are continuously generating and arriving, suppose if 3 packets arrives and satisfies the condition (proto == 150 and len <1500) then 3 threads start, whereas I only want 1 thread to start untill 10 seconds and appending these packets then sending them as a packet out message. @campovski – Trrrrrr Sep 04 '17 at 14:24
  • you have to create thread outside everything else, not inside a function... will try to make more explanatory answer – campovski Sep 04 '17 at 14:27
  • Umm, actually I want time(thread) to start whenever the first packet arrives whose proto == 150 and total_len < 1500: . This is the reason why I started a thread inside if proto.. condition. Its behavior will not be right if I start it with just after the main. As I only want time to start when the first packet arrives satisfying proto == 150 and total_len < 1500: @campovski Hope this is more clear – Trrrrrr Sep 04 '17 at 14:44
  • `.start()` just opens a new thread and doesn't do anything with it, that's why you want it to be outside of any possible loop or function (otherwise you open more threads). `.run()` runs the `target`, in our case `timeit`. That means that you want `.run()` inside a loop, when the correct packet comes and the thread isn't alive (we check that with `.isAlive()`), but `.start()` outside so it only gets executed once, at the start of script. – campovski Sep 04 '17 at 14:48
  • Umm, I am sorry but global name 'timeit' is not defined I get this error using it outside :-/ @campovski – Trrrrrr Sep 04 '17 at 15:10
  • Is the code in question the reflection of your code or the old one? – campovski Sep 04 '17 at 15:12
  • The problem is: Why do you call `aggr()` from `timeit`? `timeit` isn't meant to call any function. Check my whole answer on how `timeit` should be implemented. There might be other problems since the code is hard to read for me because there are no comments on what each part does... Sorry... – campovski Sep 04 '17 at 15:29
  • Because I want to execute the code in aggr function after 10 seconds(it aggregate the packets and send it as an output) @campovski .. I can't find any other way to do that :-/ – Trrrrrr Sep 04 '17 at 16:36
  • check my answer again... `packet_handler` is your `aggr`. `timeit` is meant to wait for 10 seconds, print each second, not call other functions. When correct packet comes, it will match if statement. Then it will check if there is a process running in a thread (`.isAlive()`). If it isn't, that is a signal that previous 10 seconds have passed, that means you have to call `aggr()`. Also, this might happen when the first correct packet comes, meaning you don't want to call `aggr`. You can add another value like `first_time=True` and if `first_time` is set to `True`, then you don't call `aggr`. – campovski Sep 04 '17 at 16:43
  • Set `first_time` to `False` at the start of `aggr` or at the end of if statement. – campovski Sep 04 '17 at 16:44
  • When I use thread outside the function then every packet whether it matches the if the condition or no is starting the thread. In my code, packets continuously keep on arriving till the application is running. @campovski – Trrrrrr Sep 05 '17 at 07:44
  • Thanks for your efforts I really appreciate. Sorry, for my complicated questions. @campovski – Trrrrrr Sep 05 '17 at 07:52