Continue to analyze mm-app.h and mm-app.cc
Mm-app.h:
// Author; Vivian
// File: mm-app.h
// Written: 08/25/10
# Include "timer-handler.h"
# Include "packet. H"
# Include "app. H"
# Include "udp-mm.h"
// Defines the measurement of the message received by the receiver.
Struct pkt_accounting {
Int last_seq; // mm message received recently
Int last_scale; // The latest sending rate confirmation message.
Int lost_pkts; // Number of packages lost upon latest confirmation
Int recv_pkts; // messages that have been received
Double RTT; // cycle
};
Class mmapp;
// The sender uses the following timer to schedule the next application to report the transfer time
Class sendtimer: Public timerhandler {
Public:
Sendtimer (mmapp * T): timerhandler (), T _ (t ){}
Inline virtual void expire (event *);
Protected:
Mmapp * T _; // point to the corresponding application class
};
// The receiver uses the following timer to determine the next ACK message transmission time.
Class acktimer: Public timerhandler {
Public:
Acktimer (mmapp * T): timerhandler (), T _ (t ){}
Inline virtual void expire (event *);
Protected:
Mmapp * T _;
};
// Multimedia application class definition
Class mmapp: Public Application {
Public:
Mmapp ();
Void send_mm_pkt (); // called by sendtimer: expire (sender)
Void send_ack_pkt (); // called by acktimer: expire (volume ER)
Protected:
Int command (INT argc, const char * const * argv );
Void start (); // start sending data packets
Void stop (); // stop sending data packets (sender)
PRIVATE:
Void Init ();
Inline double next_snd_time (); // sender
Virtual void recv_msg (INT nbytes, const char * MSG = 0); // sender/consumer er
Void set_scale (const hdr_mm * mh_buf); // sender
Void adjust_scale (void); // aggreger
Void account_recv_pkt (const hdr_mm * mh_buf); // aggreger
Void init_recv_pkt_accounting (); // aggreger
Double rate [5]; // five transmission rates
Double interval _; // application data packet transmission interval
Int pktsize _; // application data packet size
Int random _; // if 1 add randomness to the interval ??
Int running _; // if 1 application is running ??
Int seq _; // application data packet number
Int scale _; // multimedia metric Parameter
Pkt_accounting p_accnt;
Sendtimer snd_timer _;
Acktimer ack_timer _;
};
This header file mainly defines a sending timer, an ACK packet sending timer, and an mmapp class. When the timer expires, send_mm_pkt () and send_ack_pkt () of the mmapp class are called (). Next_snd_time () is used to determine the next packet sending time. Set_scale is used by the sender to determine the rate at which the mm package will be sent next time. Adjust_scale () is used by the receiver to adjust the measurement value. Account_recv_accounting is used by the receiving end to calculate the measurement value. Snd_timer _ and ack_timer _ as timer objects are now Private Members of mmapp.
Mm-app.cc: partial code information
1. // when snd_timer _ expires, call mmapp: send_mm_pkt (). T defines an object of the mmapp class in the header file.
Void sendtimer: expire (event *)
{
T _-> send_mm_pkt (); // send packets after the timer arrives
}
// When ack_timer _ expires, call mmapp: send_ack_pkt ()
Void acktimer: expire (event *)
{
T _-> send_ack_pkt ();
}
2,
// TCL Interpreter
Int mmapp: Command (INT argc, const char * const * argv)
{
TCL & TCL = TCL: instance ();
If (argc = 3 ){
If (strcmp (argv [1], "attach-agent") = 0 ){
Agent _ = (Agent *) tclobject: Lookup (argv [2]);
If (Agent _ = 0 ){
TCL. resultf ("No such agent % s", argv [2]);
Return (tcl_error );
}
// Confirm that the underlying proxy supports Multimedia Applications
If (Agent _-> supportmm () {// If suppmm mm () returns 1, it indicates the mm package
Agent _-> enablemm ();
}
Else {
TCL. resultf ("Agent \" % s \ "does not support mm application", argv [2]);
Return (tcl_error );
}
Agent _-> attachapp (this );
Return (tcl_ OK );
}
}
Return (Application: Command (argc, argv ));
}
3,
Void mmapp: Init ()
{
Scale _ = 0; // start transmission at the minimum rate
SEQ _ = 0; // the serial number of the MM report starts from 0.
Interval _ = (double) (pktsize _ <3)/(double) rate [scale _]; //? Pktsize _ <3
}
Void mmapp: Start ()
{
Init ();
Running _ = 1;
Send_mm_pkt ();
}
Void mmapp: Stop ()
{
Running _ = 0;
}
This part mainly involves some initialization work.
4,
// Send application data packets
Void mmapp: send_mm_pkt ()
{
Hdr_mm mh_buf; // defines the mh_buf variable with the hdr_mm struct
If (running _){
// The following information is written into the MM header after the package is created and passed to the udpmm proxy.
Mh_buf.ack = 0; // This Is A mm packet. If Ack is equal to 0, the mm package is used.
Mh_buf.seq = seq _ ++;
Mh_buf.nbytes = pktsize _; // the size of the MM message (instead of the UDP report size)
Mh_buf.time = Scheduler: instance (). Clock ();
Mh_buf.scale = scale _; // the current scale value. The value is 0 at initialization.
Agent _-> sendmsg (pktsize _, (char *) & mh_buf); // pass to udpmm **
// Call the send_pkt timer again,
Double next_time _ = next_snd_time (); // calculates the next packet sending time.
If (next_time _> 0) snd_timer _. resched (next_time _);
}
}
When sending a package, the application proxy needs to add the MM header to packet, and finally call the agent-> sendmsg () function to pass the package to the lower-layer udpmm proxy. Then, the task is scheduled again.
5,
// Schedule the next packet transmission time
Double mmapp: next_snd_time ()
{
Interval _ = (double) (pktsize _ <3)/(double) rate [scale _];
Double next_time _ = interval _;
If (random _) // The value of random _ 1 indicates the random start time. Otherwise, the interval _ is assigned to next_time _
Next_time _ + = interval _ * random: Uniform (-0.5, 0.5 );
Return next_time _;
}
6,
// The sender sets the scale through the receiver's notiifes
Void mmapp: set_scale (const hdr_mm * mh_buf)
{
Scale _ = mh_buf-> scale;
}
7,
Void mmapp: account_recv_pkt (const hdr_mm * mh_buf)
{
Double local_time = Scheduler: instance (). Clock ();
// Calculate the RTT
If (mh_buf-> seq = 0 ){
Init_recv_pkt_accounting ();
P_accnt.rtt = 2 * (local_time-mh_buf-> time); // RTT is the current time-the time when the sender sends the packet header
}
Else
P_accnt.rtt = 0.9 * p_accnt.rtt + 0.1*2 * (local_time-mh_buf-> time );
// Count the number of received messages and calculate the packet loss
P_accnt.recv_pkts ++;
P_accnt.lost_pkts + = (mh_buf-> seq-p_accnt.last_seq-1 );
P_accnt.last_seq = mh_buf-> seq;
}
The acceptor calculates the received information about the mm package. If the received seq is 0, the accounting () information is initialized. Otherwise, the RTT calculates the value of the first mm package, RTT is twice the receipt latency. Otherwise, RTT is calculated based on the formula p_accnt.rtt = 0.9 * p_accnt.rtt + 0.1*2 * (local_time-mh_buf-> time. In addition, you need to calculate the number of received packets, the number of dropped packets (using seq), and update the serial number of the latest received packets.
8,
Void mmapp: send_ack_pkt (void)
{
Double local_time = Scheduler: instance (). Clock ();
Adjust_scale ();
// Send the ACK message
Hdr_mm ack_buf;
Ack_buf.ack = 1; // This is a ACK packet
Ack_buf.time = local_time;
Ack_buf.nbytes = 40; // The ack report size is 40.
Ack_buf.scale = p_accnt.last_scale;
Agent _-> sendmsg (ack_buf.nbytes, (char *) & ack_buf); // send it to UDP
// Schedule the next ack time
Ack_timer.resched (p_accnt.rtt );
}
9,
Void mmapp: adjust_scale (void)
{
If (p_accnt.recv_pkts> 0 ){
If (p_accnt.lost_pkts> 0)
P_accnt.last_scale = (INT) (p_accnt.last_scale/2); // If packet loss occurs, scale by half
Else {
P_accnt.last_scale ++; // smooth network, scale + 1
If (p_accnt.last_scale> 4) p_accnt.last_scale = 4;
}
}
P_accnt.recv_pkts = 0;
P_accnt.lost_pkts = 0;
}
After the accounting information is calculated, the receiver adjusts the scale measurement value. If packet loss is found, the receiver halved the scale value set last time. If the network is smooth, the scale is increased by 1. Increase the sending rate of the sender. Of course, the maximum value is 4. At the same time, related information is cleared. Finally, an ACK packet is sent. Note that the ACK packet is sent periodically.