2016-08-07 59 views
1

Ich versuche, mein eigenes Protokoll über UDP zu implementieren.So senden Sie Pakete nach dem MTU-Wert

Wie von vielen Handbüchern im Internet vorgeschlagen, ist es besser, eine IP-Fragmentierung zu vermeiden, indem Pakete mit einer geringeren Größe als MTU gesendet werden.

Ich frage mich, was ist der beste Weg, um die optimale Größe der Nachricht zu bekommen? Soll ich irgendwie MTU-Wert bekommen (zB this) oder soll ich es einfach auf 1300 oder 1400 setzen und hoffen, dass es nicht weniger wird oder sich im Laufe der Zeit ändert?

Ich habe gehört, dass es einige Probleme gibt, MTU-Wert zu erhalten (https://en.wikipedia.org/wiki/Path_MTU_Discovery) und soweit ich weiß hängt es stark von der aktuellen Route und anderen Faktoren ab, die sich im Laufe der Zeit ändern können.

Antwort

1

Die empfohlene Größe für IPv4 UDP ist 576 Oktetts. Jeder Internet-Router soll eine IPv4-MTU von mindestens dieser Größe garantieren, und da UDP ein verbindungsloses, Fire-and-Forget-, Best-Effort- und No-Guaranteed-Delivery-Protokoll ist, riskieren Sie mit jedem Paket weniger Daten verloren gehen, und wird verlorene Pakete sein.

IPv6 hat eine Mindest-MTU-Anforderung von 1280 Oktetts und keine Fragmentierung im Pfad.

+0

Und warum Sie nicht empfehlen, die MTU während des Laufes zu bekommen -Zeit? – FrozenHeart

+0

Weil Sie keine Garantie für den Pfad haben. Höchstwahrscheinlich wird sich dieser Pfad nicht ändern, aber es kann sein, und wenn sich der Pfad ändert, kann sich die MTU ändern. Wenn Sie sich darüber Sorgen machen, setzen Sie das DF-Bit und suchen Sie nach ICMP-Fehlernachrichten darüber. Die empfohlene UDP-Größe ist keine _my_ Empfehlung. Die beste Verwendung von UDP ist mit kleinen Datagrammen, so dass wenig verloren geht, wenn Pakete verloren gehen. Deshalb haben Sprache und Video mit UDP sehr kleine Datagramme. –

+0

Auch Staus, dh Pakete fallen, _will_ ständig ändern, und es wird wahrscheinlich zu bestimmten Zeiten des Tages oder der Nacht schlechter sein. Wenn Sie eine hohe Toleranz für verlorene Daten haben, verwenden Sie eine größere Nutzlast, ansonsten halten Sie sie niedrig. –

2

Zum Abrufen der MTU in Ihrer Schnittstelle, nicht für Path MTU Discovery, haben Sie struct ifreq. Eines seiner Felder ist ifr_mtu und dieses Feld liefert Ihnen die MTU. Sie lesen dieses Feld mit ioctl, SIOCGIFMTU für die richtige Schnittstelle. (http://man7.org/linux/man-pages/man7/netdevice.7.html)

struct ifreq { 
    char ifr_name[IFNAMSIZ]; /* Interface name */ 
    union { 
     struct sockaddr ifr_addr; 
     struct sockaddr ifr_dstaddr; 
     struct sockaddr ifr_broadaddr; 
     struct sockaddr ifr_netmask; 
     struct sockaddr ifr_hwaddr; 
     short   ifr_flags; 
     int    ifr_ifindex; 
     int    ifr_metric; 
     int    ifr_mtu; 
     struct ifmap ifr_map; 
     char   ifr_slave[IFNAMSIZ]; 
     char   ifr_newname[IFNAMSIZ]; 
     char   *ifr_data; 
    }; 
}; 

Beispiel:

#include <sys/socket.h> 
#include <sys/types.h> 
#include <net/if.h> 
#include <sys/ioctl.h> 

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <errno.h> 


int main(void) 
{ 
    int sock; 
    char *name = "enp0s3"; 
    struct ifreq ifr; 

    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 
     printf("Creating socket: %d\n", errno); 
     exit(-1); 
    } 

    ifr.ifr_addr.sa_family = AF_INET; 
    strcpy(ifr.ifr_name, name); 
    if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) < 0) { 
     printf("Error ioctl: %d\n", errno); 
     exit(-2); 
    } 

    printf("MTU is %d.\n", ifr.ifr_mtu); 

    close(sock); 

    return 0; 
} 

Heute, in der Regel können Sie eine MTU von 1500 im Internet vertrauen, wenn Sie bestimmte Verbindungstechnologien wie Bluetooth oder Zigbee verwenden. Sie können Path MTU Discovery verwenden und Ihr UDP-basiertes Protokoll mit einem ACK implementieren, um zu überprüfen, ob die andere Seite die Nachricht erhalten hat. Jetzt ist die Implementierung eines ACK und Features des verbindungsorientierten Protokolls nicht dasselbe wie die Verwendung von TCP. Wenn Sie alles mit UDP machen können, ist es leichter als TCP.

Edit: Für die Verwendung von Path MTU Discovery, können Sie auch mit der Option IP_PMTUDISC_DO verwenden getsockopt:

IP_MTU_DISCOVER (since Linux 2.2) 
       Set or receive the Path MTU Discovery setting for a socket. 
       When enabled, Linux will perform Path MTU Discovery as defined 
       in RFC 1191 on SOCK_STREAM sockets. For non-SOCK_STREAM 
       sockets, IP_PMTUDISC_DO forces the don't-fragment flag to be 
       set on all outgoing packets. It is the user's responsibility 
       to packetize the data in MTU-sized chunks and to do the 
       retransmits if necessary. The kernel will reject (with 
       EMSGSIZE) datagrams that are bigger than the known path MTU. 
       IP_PMTUDISC_WANT will fragment a datagram if needed according 
       to the path MTU, or will set the don't-fragment flag 
       otherwise. 

mehr Siehe hier: http://man7.org/linux/man-pages/man7/ip.7.html

+0

"Um die MTU in Ihrer Schnittstelle zu erhalten, nicht für Path MTU Discovery" - was ist der Unterschied? – FrozenHeart

+0

@FrozenHeart, MTU Ihrer Schnittstelle bezieht sich auf die L2-Technologie des direkten LANs, mit dem Ihre Schnittstelle verbunden ist. Pfad-MTU sind alle L2-Technologien in der Mitte zwischen dieser Schnittstelle und der Zielschnittstelle (im Zielknoten), die durch die Ziel-IP-Adresse identifiziert wird. – rodolk

+0

Was ist der Grund, die MTU meiner eigenen Schnittstelle zu kennen, nicht den gesamten Netzwerkpfad? – FrozenHeart