Transmit Protocol Handler Design Pattern

来源:百度文库 编辑:神马文学网 时间:2024/05/23 11:35:11
Transmit Protocol Handler Pattern
Transmit Protocol Handler Documentation
Retransmission Buffer Documentation
Intent
Provide a common framework for transmit direction sliding window protocolimplementation.
Also Known As
Send Protocol Design Pattern
Sender Pattern
Sliding Window Transmitter Pattern
Motivation
Different sliding window protocols have a lot of similarity. This similaritycan be captured in a common design pattern for their implementation. Here wewill focus on the transmit side of the protocol.
Applicability
Transmit Protocol Handler Pattern can be used to implement protocols at anylayer.
Structure
This pattern provides a framework for implementing a sliding window protocol.The Transmit Protocol Handler receives a packet from the higher layer andtransmits it to the lower layer after assigning a sequence number. The packet isalso stored in an internal retransmission buffer. The packet is removed from theretransmission queue if the remote end acknowledges the packet. The TransmitProtocol Handler retransmits the packet if it times out for an acknowledgement.
Participants
The key actors of this design pattern:
Transmit_Protocol_Handler: Class that manages the transmit end of the protocol. This class interfaces with the receive end and the retransmission queue.
Transmit_Queue: Enqueues messages that wait for transmission when the window is full.
Retransmission_Buffer: Manages buffers until an acknowledgement is received from the other end. The messages are retransmitted If no ack is received, .
Collaboration
The following diagram shows the relationship and collaboration betweenvarious classes involved in the Transmit Protocol Handler Pattern.

Consequences
Using this pattern simplifies the implementation of transmit end point of asliding window protocol. The design is flexible enough to adjust to anyprotocol.
Implementation
The following scenarios are supported by the Transmit Protocol Handler:
Packet added to queue when window has room
Handle Transmit Request method of the Transmit Protocol Handler is invoked.
Since the transmit window is not full, packet transmission is initiated.
Protocol processing is performed on the packet. This involves the following steps: Protocol header is added to the packet
Transmit sequence number is assigned to the packet and then incremented for the next time
Receive sequence number is initialized to the last transmit sequence number of the last received packet (from the other end)
Packet is added to the Retransmission Buffer at the transmit sequence number in the packet.
Retransmission Buffer restarts AwaitAck timer.
Packet is passed to the serial port transmit queue
Packet added when window is full
Handle Transmit Request method of the Transmit Protocol Handler is invoked.
Since the transmit window is full, no further action is needed, unless the transmit window opens.
"Send Ack" request from Receive Protocol Handler
Receive Protocol Handler detects a change in the received transmit sequence number, it requests Transmit Protocol Handler to acknowledge the received packets. (The new received transmit sequence number is passed)
Transmit Protocol Handler takes the following action: If the transmission queue is empty or the transmit window is full, explicit acknowledgement is scheduled.
If transmission is pending, the acknowledgement will be piggybacked in the data packet.
"Received Ack" Notification from Receive Protocol Handler
Whenever the Receive Protocol Handler detects a change in the received receive sequence number, it informs Transmit Protocol Handler so that it can process the sequence number change as acknowledgements from the other end.
Transmit Protocol Handler takes the following action: Retransmission Buffer is informed about the acknowledged sequence numbers.
Retransmission Buffer loops through from the last acknowledged sequence number to the new sequence number and frees up the buffers as they have been acknowledged.
If no more packets are present in the retransmit buffer, AwaitAck timer is stopped.
If the window was full and has now been opened up, check the Transmit Queue for any messages that might be waiting for the window to open up.
Timeout for acknowledgement
Await Ack timer times out.
Retransmission Buffer loops through all the packets that are still pending acknowledgement and initiates retransmission.
Sample Code and Usage
Here we present the code for a typical implementation of this pattern. Codeis provided for the Transmit Protocol Handler and the Retransmission Bufferclasses. Transmit Queue can be implemented using themessagequeue pattern.
Transmit Protocol Handler
00008 00008 00009 #ifndef TRANSMIT_PROTOCOL_HANDLER_H 00010 #define TRANSMIT_PROTOCOL_HANDLER_H 00011 00012 #include "Retransmission_Buffer.h" 00013 #include "Packet_Queue.h" 00014 00023 00025 { 00026 enum {L2_HEADER_LENGTH=8}; 00027 ; 0003000033 intm_next_Receive_Sequence_Number; 0003400036Retransmission_Bufferm_retransmission_Buffer; 0003700039Packet_Queuem_transmit_Queue; 0004000042Protocol_Layer *m_p_Layer; 00043 0005500056 voidTransmit_Packet(Datagram *p_Packet) 00057 { 00058 // Add header and sequence numbers 00059 p_Packet->Add_Header(L2_HEADER_LENGTH); 00060 00061 p_Packet->Set_Receive_Sequence_Number(m_next_Receive_Sequence_Number); 00062 00063 // Fill the transmit sequence number and inform 00064 // retransmission queue if the packet is not 00065 // an acknowledgement packet 00066 if (p_Packet->GetType() != Datagram::ACKNOWLEDGEMENT) 00067 { 00068 p_Packet->Set_Transmit_Sequence_Number(m_next_Transmit_Sequence_Number); 00069 Modulo_Increment(m_next_Transmit_Sequence_Number); 00070 // Inform retransmission queue about the packet 00071m_retransmission_Buffer.Add_Packet(p_Packet); 00072 } 00073 00074 // Pass on the message for transmission to the lower layer. A pointer to the lower 00075 // layer is obtained from the parent layer. 00076Protocol_Layer *p_Lower_Layer =m_p_Layer->Get_Lower_Layer(); 00077 if (p_Lower_Layer) 00078 { 00079 p_Lower_Layer->Transmit(p_Packet); 00080 } 00081 } 00082 00083 public: 00084 0009300094Transmit_Protocol_Handler(Protocol_Layer *p_Layer) : 00095m_p_Layer(p_Layer),m_retransmission_Buffer(p_Layer) 00096 { 00097 } 00098 0010600107 voidHandle_Transmit_Request(Datagram *p_Packet) 00108 { 00109 // Check for space in window 00110 if (m_retransmission_Buffer.Get_Window_Room() == 0) 00111 { 00112 // No space, window is full. The message waits 00113 // in the queue 00114m_transmit_Queue.Add(p_Packet); 00115 } 00116 else 00117 { 00118 // If the window is open, transmit packet immediately 00119Transmit_Packet(p_Packet); 00120 } 00121 } 00122 0013300134 voidHandle_Send_Ack_Request(int new_Receive_Sequence_Number) 00135 { 00136 // Copy the new receive sequence number 00137 // to acknowledge a packet 00138m_next_Receive_Sequence_Number = new_Receive_Sequence_Number; 00139 00140 // If there are no more pending messages, 00141 // send an explicit acknowledgement message. If messages 00142 // are pending, ack can be piggy backed. 00143 if (m_transmit_Queue.Get_Length() == 0) 00144 { 00145 // No messages are pending transmission. 00146 // Send explicit ack 00147Transmit_Packet(new Datagram(Datagram::ACKNOWLEDGEMENT)); 00148 } 00149 } 00150 0016300164 voidHandle_Received_Ack_Notification(int acknowledged_Sequence_Number) 00165 { 00166 Datagram *p_Packet; 00167 00168 // Delegate ack processing to Retransmission Buffer 00169m_retransmission_Buffer.Handle_Received_Ack_Notification(acknowledged_Sequence_Number); 00170 00171 // Check if the transmit window has opened up. If there is is room in 00172 // the window, transmit packets waiting in the transmit queue 00173 int windowRoom =m_retransmission_Buffer.Get_Window_Room(); 00174 for (int i=0; i < windowRoom &&m_transmit_Queue.Get_Length(); i++) 00175 { 00176 p_Packet =m_transmit_Queue.Remove(); 00177Transmit_Packet(p_Packet); 00178 } 00179 } 00180 00181 }; 00182 #endif
Retransmission Buffer
00008 00009 #ifndef RETRANSMISSION_BUFFER_H 00010 #define RETRANSMISSION_BUFFER_H 00011 00012 #include "Datagram.h" 00013 #include "Protocol_Layer.h" 00014 00015 int Modulo_Increment(int& i); 00016 int Modulo_Difference(int seq_1, int seq_2); 00017 int Modulo_Add(int seq_1, int seq_2); 00018 0002900030 classRetransmission_Buffer 00031 { 00032 enum { WINDOW_SIZE = 512 }; 00033 00034 Datagram *m_p_Pending_Packets[WINDOW_SIZE]; 00035 int m_last_Transmitted_Sequence_Number; 00036 int m_last_Acknowledged_Sequence_Number; 00037Protocol_Layer *m_p_Layer; 00038 00039 void Restart_Await_Ack_Timer(); 00040 void Stop_Await_Ack_Timer(); 00041 00042 public: 00043 0005100052Retransmission_Buffer(Protocol_Layer *p_Layer) : m_p_Layer(p_Layer) 00053 { 00054 } 00055 0006600067 voidAdd_Packet(const Datagram *p_Packet) 00068 { 00069 00070 m_last_Transmitted_Sequence_Number = p_Packet->Get_Transmit_Sequence_Number(); 00071 00072 // Make a copy of the packet for the retransmission buffer 00073 m_p_Pending_Packets[m_last_Transmitted_Sequence_Number] = new Datagram(p_Packet); 00074 00075 // Restart the ack timer. Timer is started if its not running 00076 Restart_Await_Ack_Timer(); 00077 } 00078 0009000091 voidHandle_Received_Ack_Notification(int new_Acknowledged_Sequence_Number) 00092 { 00093 // Delete the buffers allocted to retransmission buffers 00094 // for all allocated packets. 00095 for (int i=m_last_Acknowledged_Sequence_Number; i != new_Acknowledged_Sequence_Number; 00096 Modulo_Increment(i)) 00097 { 00098 delete m_p_Pending_Packets[i]; 00099 m_p_Pending_Packets[i] = NULL; 00100 } 00101 00102 // Save the new sequence number as the last acknowledged seq num 00103 m_last_Acknowledged_Sequence_Number = new_Acknowledged_Sequence_Number; 00104 00105 // If all packets have been acknowledged, stop timer 00106 if (m_last_Transmitted_Sequence_Number == m_last_Acknowledged_Sequence_Number) 00107 { 00108 Stop_Await_Ack_Timer(); 00109 } 00110 } 00111 0011900120 intGet_Window_Room() const 00121 { 00122 // Return the room in window by determining the current count of messages 00123 // awaiting acknowledgement 00124 return (WINDOW_SIZE - 00125 Modulo_Difference(m_last_Transmitted_Sequence_Number, m_last_Acknowledged_Sequence_Number)); 00126 } 0012700137 voidHandle_Await_Ack_Timeout() 00138 { 00139 Datagram *p_Packet; 00140 00141 // Initiate retransmission of all unacknowledged packets by 00142 // looping from the last unacknowledged sequence number to 00143 // the sequence number of the last transmitted message 00144 for (int i=Modulo_Add(m_last_Acknowledged_Sequence_Number, 1); 00145 i != m_last_Transmitted_Sequence_Number; Modulo_Increment(i)) 00146 { 00147 00148 // Get the packet corresponding to the sequence number i 00149 p_Packet = m_p_Pending_Packets[i]; 00150 00151 // Pass on the message for transmission on the serial port 00152 (m_p_Layer->Get_Lower_Layer())->Transmit(p_Packet); 00153 } 00154 00155 // Now restart the timer 00156 Restart_Await_Ack_Timer(); 00157 } 00158 }; 00159 #endif
Known Uses
Datalink layer sliding window protocol implementation
Higher layer sliding window protocol implementation
Related Patterns
Receive Protocol Handler Pattern
Protocol Layer Design Pattern
Serial Port Design Pattern
High Speed Serial Port Design Pattern
Protocol Packet
Explore More...
Transmit Protocol Handler Documentation
Retransmission Buffer Documentation