Re: Problem with writing fast UDP server

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jean-Paul Calderone

    Re: Problem with writing fast UDP server

    On Fri, 21 Nov 2008 00:20:49 -0200, Gabriel Genellina <gagsl-py2@yahoo.com.a rwrote:
    >En Thu, 20 Nov 2008 14:24:20 -0200, Krzysztof Retel
    ><Krzysztof.Ret el@googlemail.c omescribió:
    >>On Nov 20, 4:00 pm, bieff...@gmail. com wrote:
    >>>On 20 Nov, 16:03, Krzysztof Retel <Krzysztof.Re.. .@googlemail.co m>
    >>>wrote:
    >>>
    >I am struggling writing fast UDP server. It has to handle around 10000
    >UDP packets per second. I started building that with non blocking
    >socket and threads. Unfortunately my approach does not work at all.
    >I wrote a simple case test: client and server. The client sends 2200
    >packets within 0.137447118759 secs. The tcpdump received 2189 packets,
    >which is not bad at all.
    >But the server only handles 700 -- 870 packets, when it is non-
    >blocking, and only 670 – 700 received with blocking sockets.
    >The client and the server are working within the same local network
    >and tcpdump shows pretty correct amount of packets received.
    >>
    >>I wonder if there is a kind of setting for socket to allow no delays?
    >
    >I've used this script to test sending UDP packets. I've not seen any
    >delays.
    >
    ><code>
    [snip]
    ></code>
    >
    >Start the server before the client.
    >
    If you want to try this program out on POSIX, make sure you change the
    time.clock() calls to time.time() calls instead, otherwise the results
    aren't very meaningful.

    I gave this a try on an AMD64 3200+ running a 32 bit Linux installation.
    Here's the results I got on the server:

    Packet count 91426
    Total bytes 8228340 bytes
    Total time 8.4 secs
    Avg size / packet 90 bytes
    Max size / packet 90 bytes
    Max time / packet 41070.9 us
    Min time / packet 79.9 us
    Avg time / packet 92.3 us
    Max speed 1100.4 Kbytes/sec
    Min speed 2.1 Kbytes/sec
    Avg speed 952.0 Kbytes/sec

    And on the client:

    Packet count 91426
    Total bytes 8228340 bytes
    Total time 8.4 secs
    Avg size / packet 90 bytes
    Max size / packet 90 bytes
    Max time / packet 40936.0 us
    Min time / packet 78.9 us
    Avg time / packet 92.3 us
    Max speed 1113.7 Kbytes/sec
    Min speed 2.1 Kbytes/sec
    Avg speed 952.1 Kbytes/sec

    Both processes ran on the same machine and communicated over localhost.

    For comparison, I tried running the client against a Twisted-based UDP
    server. Here are the results from that server:

    Packet count 91426
    Total bytes 8228340 bytes
    Total time 11.8 secs
    Avg size / packet 90 bytes
    Max size / packet 90 bytes
    Max time / packet 55393.9 us
    Min time / packet 8.8 us
    Avg time / packet 128.7 us
    Max speed 9963.2 Kbytes/sec
    Min speed 1.6 Kbytes/sec
    Avg speed 682.7 Kbytes/sec

    This seemed a bit low to me though, so I tried writing an alternate client
    and re-ran the measurement. Here are the new server results:

    Packet count 91426
    Total bytes 8228340 bytes
    Total time 2.9 secs
    Avg size / packet 90 bytes
    Max size / packet 90 bytes
    Max time / packet 38193.0 us
    Min time / packet 8.8 us
    Avg time / packet 32.2 us
    Max speed 9963.2 Kbytes/sec
    Min speed 2.3 Kbytes/sec
    Avg speed 2726.7 Kbytes/sec

    And then tried the new client against the original server, with these
    results:

    Packet count 91426
    Total bytes 8228340 bytes
    Total time 3.8 secs
    Avg size / packet 90 bytes
    Max size / packet 90 bytes
    Max time / packet 23675.0 us
    Min time / packet 6.9 us
    Avg time / packet 41.7 us
    Max speed 12711.7 Kbytes/sec
    Min speed 3.7 Kbytes/sec
    Avg speed 2109.0 Kbytes/sec

    So it does seem that handling 10k datagrams per second should be no
    problem, assuming comparable hardware, at least if whatever work you
    have to do to process each one doesn't take more than about 24 25ths
    of a millisecond (leaving you the remaining 1 part out of 25 of every
    millisecond to receive a packet).

    For reference, here's the Twisted UDP client code:

    from twisted.interne t.protocol import DatagramProtoco l
    from twisted.interne t import reactor
    from twisted.interne t.task import LoopingCall

    msg = 'xyxabc123' * 10

    class EchoClientDatag ramProtocol(Dat agramProtocol):

    def startProtocol(s elf):
    self.transport. connect('127.0. 0.1', 8000)
    LoopingCall(sel f.sendDatagrams ).start(0.00005 )

    def sendDatagrams(s elf):
    for i in xrange(50):
    self.transport. write(msg)

    def main():
    protocol = EchoClientDatag ramProtocol()
    t = reactor.listenU DP(0, protocol)
    reactor.run()

    if __name__ == '__main__':
    main()

    And here's the Twisted UDP server code:

    from time import time as clock

    from twisted.interne t.protocol import DatagramProtoco l
    from twisted.interne t import reactor

    class EchoUDP(Datagra mProtocol):
    history = []
    t0 = clock()
    def datagramReceive d(self, datagram, address):
    t1 = clock()
    self.history.ap pend((len(datag ram), t1 - self.t0))
    self.t0 = t1
    if len(self.histor y) == 91427:
    self.history.po p(0)
    show_stats(self .history)
    self.history = []

    def main():
    reactor.listenU DP(8000, EchoUDP())
    reactor.run()

    def show_stats(hist ory):
    npackets = len(history)
    bytes_total = sum([item[0] for item in history])
    bytes_avg = float(bytes_tot al) / npackets
    bytes_max = max([item[0] for item in history])
    time_total = sum([item[1] for item in history])
    time_max = max([item[1] for item in history])
    time_min = min([item[1] for item in history])
    time_avg = float(time_tota l) / npackets
    speed_max = max([item[0]/item[1] for item in history if item[1]>0])
    speed_min = min([item[0]/item[1] for item in history if item[1]>0])
    speed_avg = float(bytes_tot al) / time_total
    print "Packet count %8d" % npackets
    print "Total bytes %8d bytes" % bytes_total
    print "Total time %8.1f secs" % time_total
    print "Avg size / packet %8d bytes" % bytes_avg
    print "Max size / packet %8d bytes" % bytes_max
    print "Max time / packet %8.1f us" % (time_max*1e6)
    print "Min time / packet %8.1f us" % (time_min*1e6)
    print "Avg time / packet %8.1f us" % (time_avg*1e6)
    print "Max speed %8.1f Kbytes/sec" % (speed_max/1024)
    print "Min speed %8.1f Kbytes/sec" % (speed_min/1024)
    print "Avg speed %8.1f Kbytes/sec" % (speed_avg/1024)
    print

    if __name__ == '__main__':
    main()

  • Krzysztof Retel

    #2
    Re: Problem with writing fast UDP server

    On Nov 21, 3:52 am, Jean-Paul Calderone <exar...@divmod .comwrote:
    >
    Start the server before the client.
    >
    If you want to try this program out on POSIX, make sure you change the
    time.clock() calls to time.time() calls instead, otherwise the results
    aren't very meaningful.
    >
    I gave this a try on an AMD64 3200+ running a 32 bit Linux installation.
    Here's the results I got on the server:
    Jean-Paul, thanks very much for the code snippets.
    I have tried this out with number of tests. Both approaches are
    working fine when I run them on the same machine.
    When I run the client (twisted version) on another machine and the udp
    server (non twisted) on server machine, I got some strange behaviour.
    The client send 255 messages and than it cause an error: socket.error:
    (11, 'Resource temporarily unavailable')

    Any idea what could be wrong?

    Comment

    Working...