Search code examples
if-statementfor-looptclns2

Ns2 nodes do not make concurrent http requests


I wrote an ns2 script to run concurrent HTTP requests from 40 nodes out of 80 nodes.

However, the simulation showed one node, rather than 40 nodes, make requests to the HTTP server.

Could someone please clarify what might be wrong with the code?

The code is provided below

Thank you for your time, everyone.

set ns [new Simulator]
set clswitch [$ns node] # the access layer switch
set distrswitch [$ns node] # the distribution switch
set cch [$ns node] # the cache
set websrv [$ns node] # the web server
set traceFile [open Asim.tr w]
set namTraceFile [open Asim.nam w]
$ns namtrace-all $namTraceFile
$ns trace-all $traceFile
proc finish {} {
    global ns traceFile namTraceFile
    $ns flush-trace-all
    puts "Simulation completed."
    flush $traceFile
    flush $namTraceFile
    close $traceFile
    close $namTraceFile
    exit 0
}

for {set i 0} {$i < 80} {incr i} {
    if {$i % 2 == 0} {
        set cl ($i) [$ns node]
        $ns duplex-link $cl($i) $clswitch 100Mb 10ms DropTail
        set tcpAgent [new Agent/TCP]
        $ns attach-agent $cl($i) $tcpAgent
        set tcpSink [new Agent/TCPSink]
        $ns attach-agent $clswitch $tcpSink
        $ns connect $tcpAgent $tcpSink
        set client [new Http/Client $ns $cl($i)]
        proc start-connection {} {
            global ns client cache server
            $client connect $cache
            $cache connect $server
            $client start-session $cache $server
        }
        $ns at 0.5 "start-connection"
    }
}

$ns duplex-link $clswitch $distrswitch 100Mb 10ms DropTail
set tcpAgent [new Agent/TCP]
$ns attach-agent $clswitch $tcpAgent
set tcpSink [new Agent/TCPSink]
$ns attach-agent $distrswitch $tcpSink
$ns connect $tcpAgent $tcpSink
$ns duplex-link $distrswitch $cch 100Mb 10ms DropTail
set tcpAgent [new Agent/TCP]
$ns attach-agent $distrswitch $tcpAgent
set tcpSink [new Agent/TCPSink]
$ns attach-agent $cch $tcpSink
$ns connect $tcpAgent $tcpSink
$ns duplex-link $cch $websrv 100Mb 10ms DropTail
set tcpAgent [new Agent/TCP]
$ns attach-agent $cch $tcpAgent
set tcpSink [new Agent/TCPSink]
$ns attach-agent $websrv $tcpSink
$ns connect $tcpAgent $tcpSink
set server [new Http/Server $ns $websrv]
set cache [new Http/Cache $ns $cch]
set pgp [new PagePool/Math]
set tmp [new RandomVariable/Constant]
$tmp set val_ 4096
$pgp ranvar-size $tmp
set tmp [new RandomVariable/Exponential]
$tmp set avg_ 6
$pgp ranvar-age $tmp
$server set-page-generator $pgp
set tmp [new RandomVariable/Exponential]
$tmp set avg_ 0.5
$client set-interval-generator $tmp
$client set-page-generator $pgp 
$ns at 6.0 "finish"

Solution

  • The problem is in this code:

    for {set i 0} {$i < 80} {incr i} {
        if {$i % 2 == 0} {
            set cl ($i) [$ns node]
            $ns duplex-link $cl($i) $clswitch 100Mb 10ms DropTail
            set tcpAgent [new Agent/TCP]
            $ns attach-agent $cl($i) $tcpAgent
            set tcpSink [new Agent/TCPSink]
            $ns attach-agent $clswitch $tcpSink
            $ns connect $tcpAgent $tcpSink
            set client [new Http/Client $ns $cl($i)]
            proc start-connection {} {
                global ns client cache server
                $client connect $cache
                $cache connect $server
                $client start-session $cache $server
            }
            $ns at 0.5 "start-connection"
        }
    }
    

    First off, you're defining a procedure inside a loop. That's a bad indication right there (since you're not doing complex runtime code generation). But the real problem is that while you're creating many clients, you're trying to store them all in the same simple variable:

            set client [new Http/Client $ns $cl($i)]
    

    Each time through the loop, this gets overwritten; only the last such client will get started. What we need to do is to pass the client to the procedure by an argument.

    ##### MOVED, AND client IS NOW AN ARGUMENT, NOT A GLOBAL #####
    proc start-connection {client} {
        global ns cache server
        $client connect $cache
        $cache connect $server
        $client start-session $cache $server
    }
    
    ##### Now same as above... except for a couple of lines #####
    for {set i 0} {$i < 80} {incr i} {
        if {$i % 2 == 0} {
            set cl ($i) [$ns node]
            $ns duplex-link $cl($i) $clswitch 100Mb 10ms DropTail
            set tcpAgent [new Agent/TCP]
            $ns attach-agent $cl($i) $tcpAgent
            set tcpSink [new Agent/TCPSink]
            $ns attach-agent $clswitch $tcpSink
            $ns connect $tcpAgent $tcpSink
            set client [new Http/Client $ns $cl($i)]
            ##### THE NEXT LINE IS CHANGED FROM YOUR CODE! #####
            $ns at 0.5 [list start-connection $client]
            ##### KEEP TRACK OF ALL THE CLIENTS #####
            lappend allClients $client
        }
    }
    

    We also need to do a little work later on, where you refer to the “client” in some lower code. The work just needs to be done in a loop iterating over the list of clients.

    foreach client $allClients {
        $client set-interval-generator $tmp
        $client set-page-generator $pgp 
    }
    

    Lists are a great way of keeping a simple collection of things.