日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

QualNet收发包过程分析(一)

發布時間:2023/12/8 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QualNet收发包过程分析(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

因項目需要,對QualNet仿真中節點間收發包行為進行了仔細研究,并不斷添加一些輸出以驗證思路。應該說,大致是正確的,可能有些細節研究還不夠透徹。對一般的應用協議開發已經夠用了,如果想制作一個完整的組件添加進去,還需進一步深入。

以下以發送端節點向接收端節點發送應用層消息為例,介紹QualNet收發包過程。

1. 發送端

1.1 應用層

創建傳輸層UDP協議消息MSG_TRANSPORT_FromAppSend,添加了信息字段AppToUdpSend,發送(即調度傳輸層處理該消息)。函數見~/main/app_util.cpp

void APP_UdpSendNewHeaderData(Node *node,AppType appType,NodeAddress sourceAddr,short sourcePort,NodeAddress destAddr,char *header,int headerSize,char *payload,int payloadSize,clocktype delay,TraceProtocolType traceProtocol) {Message *msg;AppToUdpSend *info;msg = MESSAGE_Alloc(node,TRANSPORT_LAYER,TransportProtocol_UDP,MSG_TRANSPORT_FromAppSend);MESSAGE_PacketAlloc(node, msg, payloadSize, traceProtocol);memcpy(MESSAGE_ReturnPacket(msg), payload, payloadSize);MESSAGE_AddHeader(node, msg, headerSize, traceProtocol);memcpy(MESSAGE_ReturnPacket(msg), header, headerSize);MESSAGE_InfoAlloc(node, msg, sizeof(AppToUdpSend));info = (AppToUdpSend *) MESSAGE_ReturnInfo(msg);SetIPv4AddressInfo(&info->sourceAddr, sourceAddr);info->sourcePort = sourcePort;SetIPv4AddressInfo(&info->destAddr, destAddr);info->destPort = (short) appType;info->priority = APP_DEFAULT_TOS;info->outgoingInterface = ANY_INTERFACE;info->ttl = IPDEFTTL;MESSAGE_Send(node, msg, delay); }

1.2 傳輸層

應用層調度了傳輸層消息,由~/main/transport.cpp中消息處理函數TRANSPORT_ProcessEvent處理。如下所示,根據消息的協議類型選擇具體協議處理,條理清晰。

void TRANSPORT_ProcessEvent(Node * node, Message * msg) {switch (MESSAGE_GetProtocol(msg)){case TransportProtocol_UDP: {TransportUdpLayer(node, msg);break;}case TransportProtocol_TCP: {TransportTcpLayer(node, msg);break;}case TransportProtocol_RSVP:...... } }

UDP消息處理函數TransportUdpLayer如下所示,再根據消息類型選擇具體處理方式。

void TransportUdpLayer(Node *node, Message *msg) {switch (msg->eventType){case MSG_TRANSPORT_FromNetwork:{TransportUdpSendToApp(node, msg);break;}case MSG_TRANSPORT_FromAppSend:{TransportUdpSendToNetwork(node, msg);break;}default:assert(FALSE);abort();} }

傳輸層向網絡層發送數據,消息類型MSG_TRANSPORT_FromAppSend,調用函數TransportUdpSendToNetwork。在函數中添加了UDP首部TransportUdpHeader,調用網絡層函數接收數據包。如下所示。

void TransportUdpSendToNetwork(Node *node, Message *msg) {TransportDataUdp *udp = (TransportDataUdp *) node->transportData.udp;TransportUdpHeader *udpHdr;AppToUdpSend *info;unsigned char protocol = IPPROTO_UDP;info = (AppToUdpSend *) MESSAGE_ReturnInfo(msg);MESSAGE_AddHeader(node, msg, sizeof(TransportUdpHeader), TRACE_UDP);udpHdr = (TransportUdpHeader *) msg->packet;udpHdr->sourcePort = info->sourcePort;udpHdr->destPort = info->destPort;udpHdr->length = (unsigned short) MESSAGE_ReturnPacketSize(msg);udpHdr->checksum = 0; //調用網絡層函數接收數據NetworkIpReceivePacketFromTransportLayer(node,msg,info->sourceAddr,info->destAddr,info->outgoingInterface,info->priority,protocol,FALSE,info->ttl); }

1.3 網絡層

1.3.1 基本操作

~/libraries/developer/src/network_ip.cpp中,函數NetworkIpReceivePacketFromTransportLayer有兩個,區別在于源和目的地址參數的類型,一個是NodeAddress,另一個是Address。消息的信息字段類型AppToUdpSend中,info->sourceAddress是Address型地址。調用函數NetworkIpReceivePacketFromTransportLayer,判斷網絡層協議類型,采取相應動作。如下所示:

void NetworkIpReceivePacketFromTransportLayer(Node *node,Message *msg,Address sourceAddress,Address destinationAddress,int outgoingInterface,TosType priority,unsigned char protocol,BOOL isEcnCapable,UInt8 ttl) {NetworkDataIp *ip = (NetworkDataIp *) node->networkData.networkVar;ip->isPacketEcnCapable = isEcnCapable;//判斷網絡協議類型if (((node->networkData.networkProtocol == IPV4_ONLY ) ||(node->networkData.networkProtocol == DUAL_IP))&& (sourceAddress.networkType == NETWORK_IPV4)&& (destinationAddress.networkType == NETWORK_IPV4)){NetworkIpSendRawMessage(node,msg,GetIPv4Address(sourceAddress),GetIPv4Address(destinationAddress),outgoingInterface,priority,protocol,ttl,FALSE);}else if (((node->networkData.networkProtocol == IPV6_ONLY) ||(node->networkData.networkProtocol == DUAL_IP))&& (sourceAddress.networkType == NETWORK_IPV6)&& (destinationAddress.networkType == NETWORK_IPV6)){...... }...... }

~/libraries/developer/src/network_ip.cpp中函數NetworkIpSendRawMessage,如下所示。先按指定參數確定出接口,如果參數是任意接口,則判斷是否廣播。非廣播,按指向源地址的接口為出接口;廣播,按目的地址找出接口。若不是任意接口,則按指定的接口來發送。第二步,添加IP首部(AddIpHeader函數調用MESSAGE_AddHeader添加首部IpHeaderType,不再贅述),第三步,調用路由協議發送數據包。在1.1中應用層添加的信息字段AppToUdpSend,info->outgoingInterface =?ANY_INTERFACE,

void NetworkIpSendRawMessage(Node *node,Message *msg,NodeAddress sourceAddress,NodeAddress destinationAddress,int outgoingInterface,TosType priority,unsigned char protocol,unsigned ttl) {NodeAddress newSourceAddress;int interfaceIndex;NetworkDataIp* ip = (NetworkDataIp *) node->networkData.networkVar;//由參數指定的出接口,查找接口索引if (outgoingInterface == ANY_INTERFACE){ if (sourceAddress != ANY_IP){interfaceIndex = NetworkIpGetInterfaceIndexFromAddress(node, sourceAddress);newSourceAddress = sourceAddress;if ((interfaceIndex == -1) || (newSourceAddress == (unsigned)-1)){MESSAGE_Free(node, msg);return;}}else{interfaceIndex = NetworkGetInterfaceIndexForDestAddress(node,destinationAddress);newSourceAddress = NetworkIpGetInterfaceAddress(node,interfaceIndex);if ((interfaceIndex == -1) || (newSourceAddress == (unsigned)-1)){MESSAGE_Free(node, msg);return;}}}else{interfaceIndex = outgoingInterface;newSourceAddress = sourceAddress;}AddIpHeader(node,msg,newSourceAddress,destinationAddress,priority,protocol,ttl);RoutePacketAndSendToMac(node, msg, CPU_INTERFACE, interfaceIndex, ANY_IP);} }

1.3.2 區分發送類型

RoutePacketAndSendToMac函數很關鍵,在網絡層和MAC層之間有承前啟后的作用。先由入口接口判斷是首發還是轉發,再由目的地址判斷是廣播、組播還是單播,分別進行處理。參數傳遞:incomingInterface = CPU_INTERFACE, previousHopAddress = ANY_IP。

void RoutePacketAndSendToMac(Node *node,Message *msg,int incomingInterface,int outgoingInterface,NodeAddress previousHopAddress) {NetworkDataIp *ip = (NetworkDataIp *) node->networkData.networkVar;NetworkForwardingTable* rt = &(ip->forwardTable);IpHeaderType *ipHeader = (IpHeaderType *) msg->packet;int outgoingInterfaceToUse;int interfaceIndex;NodeAddress outgoingBroadcastAddress; //由入口接口判斷是本地消息還是轉發消息if (incomingInterface == CPU_INTERFACE){//本節點發出的消息interfaceIndex = outgoingInterface;}else{//轉發其他節點的消息.interfaceIndex = incomingInterface;}//由入口接口和目的地址判斷網絡行為//節點自環if (ip->isLoopbackEnabled && (incomingInterface == CPU_INTERFACE) &&NetworkIpLoopbackLoopbackUnicastsToSender(node, msg)){ }//以任意目的地址廣播else if (ipHeader->ip_dst == ANY_DEST){NetworkIpSendPacketOnInterface(node,msg,incomingInterface,outgoingInterface,ipHeader->ip_dst);}//以出口接口的廣播地址廣播else if (IsOutgoingBroadcast(node,ipHeader->ip_dst,&outgoingInterfaceToUse,&outgoingBroadcastAddress)){ NetworkIpSendPacketOnInterface(node,msg,incomingInterface,outgoingInterfaceToUse,outgoingBroadcastAddress);}//利用組播路由進行組播else if (NetworkIpIsMulticastAddress(node, ipHeader->ip_dst)){...... }//利用單播路由進行單播else{ BOOL packetWasRouted = FALSE;if (!packetWasRouted){RouterFunctionType routerFunction = NULL;//查找接口路由協議routerFunction = NetworkIpGetRouterFunction(node,interfaceIndex);if (routerFunction){//路由發送(routerFunction)(node,msg,ipHeader->ip_dst,previousHopAddress,&packetWasRouted);}if (!packetWasRouted){//按轉發表發送數據包RouteThePacketUsingLookupTable(node,msg,incomingInterface);}}} }

以單播,接口路由協議為AODV4為例,NetworkIpGetRouterFunction將返回函數指針Aodv4RouterFunction(過程略),Aodv4RouterFunction函數調用AodvRouterFunction函數進行路由發送。參數傳遞:destAddr = ipHeader->ip_dst, previousHopAddress = ANY_IP, packetWasRouted = FALSE。

1.判斷本節點地址是否是目的地址,是則不需路由,packetWasRouted = FALSE,不是則需要路由。

2.判斷本節點地址是否源地址,是則查找路由發送,不是則調用AodvHandleData函數接收或轉發。

3.查找路由,如果有就直接發送,沒有則看是否已經發送路由請求信息。

4.沒有路由情況,看是否已發送路由請求信息,未發送則立即發送,已發送說明確實沒有此路由,數據包將無法發出。

void AodvRouterFunction(Node* node,Message* msg,Address destAddr,Address previousHopAddress,BOOL* packetWasRouted) {AodvData* aodv=NULL;IpHeaderType* ipHeader = NULL;ip6_hdr* ip6Header = NULL;Address sourceAddress;BOOL IPV6 = FALSE;if (destAddr.networkType == NETWORK_IPV6){ }else{aodv = (AodvData *) NetworkIpGetRoutingProtocol(node,ROUTING_PROTOCOL_AODV,NETWORK_IPV4);ipHeader = (IpHeaderType *) MESSAGE_ReturnPacket(msg);SetIPv4AddressInfo(&sourceAddress,ipHeader->ip_src);}//判斷本節點是否目的地址,確定是否需要路由if (AodvIpIsMyIP(node, destAddr)){*packetWasRouted = FALSE;}else{*packetWasRouted = TRUE;}//判斷本節點是路由的中間節點還是目的節點//本節點不是源節點if (!AodvIpIsMyIP(node, sourceAddress)){ //如果是目的節點就接收,如果是中間節點就轉發AodvHandleData(node, msg, destAddr, previousHopAddress);}//本節點是源節點else{//不需要路由 if (!(*packetWasRouted)) //AodvIpIsMyIP(node, destAddr)){return;}//查看是否有至目的地址的路由rtToDest = AodvCheckRouteExist(destAddr,&aodv->routeTable,&isValidRt);//有合法路由,則發送數據if (isValidRt){ AodvTransmitData(node, msg, rtToDest, previousHopAddress);}//沒有合法路由,且沒有發送RREQ消息else if (!AodvCheckSent(destAddr, &aodv->sent)){ AodvInsertBuffer(node,msg,destAddr,previousHopAddress,&aodv->msgBuffer); AodvInitiateRREQ(node, destAddr);}//沒有合法路由,且RREQ已經發送else{ AodvInsertBuffer(node,msg,destAddr,previousHopAddress,&aodv->msgBuffer);}} }

考慮節點首發情況,調用函數AodvTransmitData發送數據。更改消息層為MAC層,事件為MAG_MAC_FromNetwork,檢查和更新路由有效時間,調用函數NetworkIpSendPacketToMacLayer發送數據。

static void AodvTransmitData(Node* node,Message* msg,AodvRouteEntry* rtEntryToDest,Address previousHopAddress) {AodvData* aodv = NULL;IpHeaderType* ipHeader = NULL;ip6_hdr* ip6Header = NULL;Address src;Address dst;BOOL IPV6 = FALSE;if (previousHopAddress.networkType == NETWORK_IPV6){ }else{aodv = (AodvData*)NetworkIpGetRoutingProtocol(node, ROUTING_PROTOCOL_AODV,NETWORK_IPV4);ipHeader = (IpHeaderType*) MESSAGE_ReturnPacket(msg);SetIPv4AddressInfo(&src,ipHeader->ip_src);SetIPv4AddressInfo(&dst,rtEntryToDest->destination.interfaceAddr.ipv4);}MESSAGE_SetLayer(msg, MAC_LAYER, 0);MESSAGE_SetEvent(msg, MSG_MAC_FromNetwork);//路由有效時間if (rtEntryToDest->lifetime < getSimTime(node) + AODV_ACTIVE_ROUTE_TIMEOUT){rtEntryToDest->lifetime = getSimTime(node) + AODV_ACTIVE_ROUTE_TIMEOUT;AodvMoveRouteEntry(&aodv->routeTable, rtEntryToDest);}//更新路由有效時間if (((previousHopAddress.interfaceAddr.ipv4 != ANY_IP)&& (previousHopAddress.networkType == NETWORK_IPV4))|| ((!IS_MULTIADDR6(previousHopAddress.interfaceAddr.ipv6))&& (previousHopAddress.networkType == NETWORK_IPV6))){AodvUpdateLifetime(node,aodv,previousHopAddress,&aodv->routeTable,1);}if (!Address_IsSameAddress(&previousHopAddress,&src)){AodvUpdateLifetime(node,aodv,src,&aodv->routeTable,-1);}AodvUpdateLifetime(node,aodv,rtEntryToDest->nextHop,&aodv->routeTable,1);if (IPV6){ }else{NetworkIpSendPacketToMacLayer(node,msg,rtEntryToDest->outInterface,rtEntryToDest->nextHop.interfaceAddr.ipv4);} }

1.3.3 分片處理?

NetworkIpSendPacketToMacLayer函數直接調用NetworkIpSendPacketOnInterface函數。在NetworkIpSendPacketOnInterface函數中,主要作用是判斷是否需要分片傳輸,分片則逐片發送后刪除原消息,不分片則將原消息調用NetworkIpSendOnBackplane函數直接發送。

void NetworkIpSendPacketOnInterface(Node *node,Message *msg,int incomingInterface,int outgoingInterface,NodeAddress nextHop) {NetworkDataIp *ip = (NetworkDataIp *) node->networkData.networkVar;NetworkDataIcmp *icmp = (NetworkDataIcmp*) ip->icmpStruct;IpHeaderType *ipHeader = (IpHeaderType *) msg->packet; int interfaceIndex;if (incomingInterface == CPU_INTERFACE)interfaceIndex = outgoingInterface;elseinterfaceIndex = incomingInterface;ipHeader = (IpHeaderType*) MESSAGE_ReturnPacket(msg);//獲取接口所連通信信道最大傳輸字節數int fragInterface = NetworkIpGetSmallestFragUnitInterface(node);if (MESSAGE_ReturnPacketSize(msg) > GetNetworkIPFragUnit(node, fragInterface)){//看ip首部中是否允許分片,不允許,則發送ICMP消息if (IpHeaderGetIpDontFrag(ipHeader ->ipFragment)){if (ip->isIcmpEnable && icmp->fragmentationNeededEnable){//發送ICMP消息BOOL ICMPErrorMsgCreated = NetworkIcmpCreateErrorMessage(node,msg,ipHeader->ip_src,incomingInterface,ICMP_DESTINATION_UNREACHABLE,ICMP_DGRAM_TOO_BIG,0,0); MESSAGE_Free(node,msg);return;}}}//不分片情況if (!fragmentedByIP){NetworkIpSendOnBackplane(node,msg,incomingInterface,outgoingInterface,nextHop);}//分片情況else{if (fragHead){int fragId = 0 ;//逐片發送while (fragHead){ipHeader = (IpHeaderType *) fragHead->msg->packet; NetworkIpSendOnBackplane(node,fragHead->msg,incomingInterface,outgoingInterface,nextHop);tempFH = fragHead;fragHead = fragHead->next;MEM_free(tempFH);} //分片發送后,原消息釋放MESSAGE_Free(node, msg);return;}} }

文章太長了,從NetworkIpSendOnBackplane函數開始,另文敘述。

總結

以上是生活随笔為你收集整理的QualNet收发包过程分析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。