2016-08-07 6 views
1

Я пытаюсь реализовать собственный протокол по протоколу UDP.Как отправить пакеты в соответствии со значением MTU

Как было предложено многими руководствами в Интернете, лучше избегать фрагментации IP, отправив пакеты с их размерами меньше MTU.

Интересно, какой лучший способ получить оптимальный размер сообщения? Должен ли я каким-то образом получить значение MTU (например, this), или я должен просто установить его как 1300 или 1400, и надеемся, что он не будет меньше или будет меняться со временем?

Я слышал, что есть некоторые проблемы с получением значения MTU (https://en.wikipedia.org/wiki/Path_MTU_Discovery), и насколько я знаю, он сильно зависит от текущего маршрута и других факторов, которые могут меняться со временем.

ответ

1

Рекомендуемый размер для IPv4 UDP - 576 октетов. Каждый интернет-маршрутизатор должен гарантировать MTU IPv4, по крайней мере, такого размера, и поскольку протокол UDP является протоколом без установления соединения, протокола «пожар-и-забыть», «лучше всего», без гарантии, вы рискуете меньшим количеством данных с каждым пакетом, который может быть потерянным, а там будет потерянными пакетами.

IPv6 имеет минимальное требование MTU в 1280 октетов и отсутствие фрагментации на пути.

+0

А почему бы вам не рекомендуем, чтобы получить MTU во время бега -время? – FrozenHeart

+0

Потому что у вас нет гарантии пути. Скорее всего, этот путь не изменится, но может, и если путь изменится, MTU может измениться. Если вы беспокоитесь об этом, установите бит DF и найдите сообщения об ошибках ICMP. Рекомендуемый размер UDP не является рекомендацией _my_. Наилучшее использование UDP - это небольшие дейтаграммы, так что мало теряется, когда пакеты теряются. Вот почему голос и видео с использованием UDP имеют очень маленькие дейтаграммы. –

+0

Кроме того, перегрузка, означающая падение пакетов, _will_ постоянно меняется, и, вероятно, будет хуже в определенное время дня или ночи. Если у вас высокий уровень допуска к потерянным данным, используйте большую полезную нагрузку, иначе держите ее на низком уровне. –

2

Для получения MTU в вашем интерфейсе, а не для обнаружения MTU пути, у вас есть struct ifreq. Одно из полей - ifr_mtu, и это поле предоставит вам MTU. Вы читаете это поле с помощью ioctl, SIOCGIFMTU для правильного интерфейса. (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; 
    }; 
}; 

Пример:

#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; 
} 

Сегодня, в общем, вы можете доверять MTU 1500 человек в Интернете, если вы не используете специальные технологии соединения, такие как Bluetooth или Zigbee. Вы можете использовать Path MTU Discovery и реализовать свой протокол на основе UDP с помощью ACK, чтобы проверить, получила ли другая сторона сообщение. Теперь реализация ACK и функций протокола, ориентированного на соединение, не совпадает с использованием TCP. Если вы можете делать все с UDP, оно легче TCP.

Edit: Для использования Path MTU Discovery, вы можете также использовать getsockopt с опцией IP_PMTUDISC_DO:

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. 

Подробнее здесь: http://man7.org/linux/man-pages/man7/ip.7.html

+0

«Для получения MTU в вашем интерфейсе, а не для обнаружения пути MTU» - в чем разница? – FrozenHeart

+0

@FrozenHeart, MTU вашего интерфейса относится к технологии L2 непосредственной локальной сети, где подключен ваш интерфейс. Path MTU - это все технологии L2 в середине между этим интерфейсом и целевым интерфейсом (в узле назначения), идентифицированным IP-адресом назначения. – rodolk

+0

Какой смысл знать MTU моего собственного интерфейса, а не весь сетевой путь? – FrozenHeart