1

UDP 経由で独自のプロトコルを実装しようとしています。

インターネットの多くのマニュアルで示唆されているように、MTU 未満のサイズのパケットを送信して IP フラグメンテーションを回避することをお勧めします。

メッセージの最適なサイズを取得する最良の方法は何ですか? どうにかして MTU 値を取得する必要がありますか (たとえば、このように)、または 1300 や 1400 のように単純に設定し、時間の経過とともに減少したり変化したりしないようにする必要がありますか?

MTU 値 ( https://en.wikipedia.org/wiki/Path_MTU_Discovery )を取得する際にいくつかの問題があると聞きましたが、私の知る限り、現在のルートや時間の経過とともに変化する可能性のあるその他の要因に大きく依存しています。

4

2 に答える 2

2

IPv4 UDP の推奨サイズは 576 オクテットです。各インターネット ルーターは、少なくともそのサイズの IPv4 MTU を保証することになっています。UDP はコネクションレス、ファイア アンド フォーゲット、ベスト エフォート、非保証配信プロトコルであるため、各パケットのデータのリスクが少なくなる可能性があります。失われ、パケットが失われます

IPv6 の最小 MTU 要件は 1280 オクテットで、パスにフラグメンテーションはありません。

于 2016-08-07T18:16:06.497 に答える
2

パス MTU の検出ではなく、インターフェイスで MTU を取得するには、構造体 ifreq があります。そのフィールドの 1 つは 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;
}

今日では、Bluetooth や Zigbee などの特定の接続テクノロジを使用しない限り、一般にインターネットで 1,500 の MTU を信頼できます。Path MTU Discovery を使用し、ACK を使用して UDP ベースのプロトコルを実装して、相手側がメッセージを受信したことを確認できます。現在、ACK と接続指向プロトコルの機能を実装することは、TCP を使用することと同じではありません。UDP ですべてを行うことができれば、TCP よりも軽量です。

編集: Path MTU Discovery を使用するには、オプション IP_PMTUDISC_DO で 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.

詳細はこちら: http://man7.org/linux/man-pages/man7/ip.7.html

于 2016-08-07T18:36:41.127 に答える