/* * The headers are converted to a string to send * The maximum number of digits in 32-bit decimal is 10 digits: 4,294,967,296 * The maximum number of digits in 64-bit decimal is 20 digits: 18,446,744,073,709,551,616 * The maximum number of digits in 16-bit decimal is 5 digits: 65,536 * There are 8 bits of identification * There are also 6 spaces */ int MyUdpSeg::maxHeadSize = 10 + 20 + 20 + 5 + 5 + 8 + 6;
//Constructor 1: Construct class objects based on data MyUdpSeg::MyUdpSeg(constchar* buf, num_type Number, off_type Offset, len_type Length, tag_type Tag, win_type Window, id_type Id) : data(buf), number(Number), offset(Offset), window(Window), length(Length), id(Id), tag(Tag) {}
//Constructor 2: Construct class objects based on the complete UDP packet segment(string) MyUdpSeg::MyUdpSeg(string& udpSeg) { vector<string> vec = parse(udpSeg); // error packet segment if (vec.size() < 6) { length = 0; //Indicates that this is a useless package return; } /* * have not string to unsigned int or size_t function * but string to unsigned long is satisfiable * just make sure it doesn't overflow * use forced transformation to ignore warnings */ number = num_type(stoul(vec[0])); offset = off_type(stoul(vec[1])); window = win_type(stoul(vec[2])); length = len_type(stoul(vec[3])); id = id_type(stoul(vec[4])); tag = tag_type(vec[5]); if (vec.size() > 6) //if arry data. ACK may not carry data data = vec[6]; }
//Constructor 3: Retransmit, adjust the number MyUdpSeg::MyUdpSeg(MyUdpSeg& udpSeg, num_type Number) : data(udpSeg.data), number(Number), offset(udpSeg.offset), window(udpSeg.window), length(udpSeg.length), id(udpSeg.id), tag(udpSeg.tag) {}
//parse the string vector<string> MyUdpSeg::parse(string& str) { //Note that there are also spaces in the data, so parse up to six times //Data should not be sliced int spaceNum = 6;
str = str + " "; //add an space vector<string> res; size_t pos = 0; size_t pos1; while ((pos1 = str.find(' ', pos)) != string::npos) { if (spaceNum-- == 0) break;
res.push_back(str.substr(pos, pos1 - pos)); while (str[pos1] == ' ') pos1++; pos = pos1; } //Get complete data string data = str.substr(pos); if (data != "") res.push_back(data);
return res; //move construction }
//convert to string to send data string MyUdpSeg::seg_to_string() { string res; res += to_string(number) + " "; res += to_string(offset) + " "; res += to_string(window) + " "; res += to_string(length) + " "; res += to_string(id) + " "; res += tag.to_string() + " "; //std::bitset::to_string() res += data; return res; }
structtimerNode { MyUdpSeg::num_type number; //segment number MyUdpSeg::off_type offset; //data offset chrono::system_clock::time_point time; //start time bool timeout; //timeout flag timerNode(MyUdpSeg::num_type Number, MyUdpSeg::off_type Offset) : number(Number), offset(Offset),time(chrono::system_clock::now()), timeout(false) {} timerNode(const timerNode& node) : number(node.number), offset(node.offset),time(node.time), timeout(false) {} booloperator==(MyUdpSeg::num_type Number) { return number == Number; } //for find() function or remove() };
classTimerList { public: using node_type = timerNode; using rtt_type = unsignedint; using rto_type = double; using timerIter = list<node_type>::iterator; private: list<node_type> timerList; public: TimerList(){} ~TimerList(){} //insert by node voidinsertTimer(const node_type& node); //insert by number voidinsertTimer(MyUdpSeg::num_type Number, MyUdpSeg::off_type Offset);
//delete by number, return RTT/ms rtt_type deleteTimer(MyUdpSeg::num_type Number);
//deal with timeout packets, return numbers vector<MyUdpSeg::num_type> tick(rto_type RTO);
//return size size_tsize(){ return timerList.size(); } private: //delete all by offset, call by "rtt_type deleteTimer(MyUdpSeg::num_type Number);" voiddeleteTimer_(MyUdpSeg::off_type Offset); };
voidTimerList::insertTimer(const node_type& node) { timerList.push_back(node); // call move or copy constructor function, not need to construct } voidTimerList::insertTimer(MyUdpSeg::num_type Number, MyUdpSeg::off_type Offset) { timerList.emplace_back(Number, Offset); //call constructor function }
TimerList::rtt_type TimerList::deleteTimer(MyUdpSeg::num_type Number) { //find the node timerIter iter = find(timerList.begin(), timerList.end(), Number); //O(n) if (iter == timerList.end()) //not found return0; //zero used to error detect
//delete node with the same offset deleteTimer_(offset);
return RTT; }
voidTimerList::deleteTimer_(MyUdpSeg::off_type Offset) { for (timerIter iter = timerList.begin(); iter != timerList.end();) { if ((*iter).offset == Offset) iter = timerList.erase(iter); //erase return next iterator else iter++; } }
vector<MyUdpSeg::num_type> TimerList::tick(rto_type RTO) { if (RTO <= 0) return{};
vector<MyUdpSeg::num_type> number_retrans; for (timerIter iter = timerList.begin(); iter != timerList.end(); iter++) { if ((*iter).timeout == true) continue; else { chrono::system_clock::time_point nowtime = chrono::system_clock::now(); rtt_type interval = rtt_type(chrono::duration_cast<chrono::milliseconds>(nowtime - (*iter).time).count()); if (interval > RTO) //need to retransmit { number_retrans.push_back((*iter).number); (*iter).timeout = true; } } } return number_retrans; }
//lambda for remove_if auto pred_lambda = [](bufferNode& bufNode, MyUdpSeg::off_type offset) -> bool// "-> bool" is omittable { return bufNode.udpSeg.getOffset() == offset; }; auto pred = bind(pred_lambda,std::placeholders::_1, myOffset);
//the simplified form is as follows auto pred = bind([](bufferNode& bufNode, MyUdpSeg::off_type offset) { //lambda return bufNode.udpSeg.getOffset() == offset; }, placeholders::_1, myOffset); //parameters
classBufferList { public: using node_type = bufferNode; using bufferIter = list<node_type>::iterator; using node_return_type = pair<node_type&, bool>; private: list<node_type> bufferList; public: BufferList(){} ~BufferList(){}
//insert node voidinsertNode(MyUdpSeg& UdpSeg); voidinsertNode(MyUdpSeg&& UdpSeg); voidinsertNode(MyUdpSeg& UdpSeg, MyUdpSeg::num_type Number); voidsortInsertNode(MyUdpSeg& UdpSeg); //insert sorted by offset(used by recvbuf)
//delete by number voiddeleteNode(MyUdpSeg::num_type Number);
//get node by number, return pair: reference、bool (to check node) node_return_type getNode(MyUdpSeg::num_type Number); /* * Note for getNode function: * For each return value, initialize it with a new variable * Do not assign a value to pair again after initialization, it will act on the initialized node */