Как найти самый большой пакет UDP, который я могу отправить без фрагментации?
Мне нужно знать, какой самый большой UDP-пакет, который я могу отправить на другой компьютер, не имеет фрагментации.
Этот размер обычно известен как MTU (Maximum Transmission Unit). Предположительно, между двумя компьютерами будет много маршрутизаторов и модемов, которые могут иметь разные MTU.
Я прочитал, что реализация TCP в Windows автоматически находит максимальный MTU в пути.
Я также экспериментировал, и я узнал, что максимальный MTU с моего компьютера на сервер составлял 57712 байтов + заголовок. Все, что выше этого, было отброшено. Мой компьютер находится в локальной сети, а не MTU должен быть около 1500 байт?
Ответы
Ответ 1
Следующее не отвечает на ваш вопрос напрямую, но вам может показаться интересным; в нем говорится, что IP-пакеты могут быть разобраны/собраны и, следовательно, больше, чем предел на нижнем носителе (например, 1500-байтовый Ethernet): Разрешить фрагментацию IP, MTU, MSS, и вопросы PMTUD с GRE и IPSEC
Подробнее об этой теме:
- Re: UDP-фрагментация говорит, что вы должны использовать ICMP вместо UDP для обнаружения MTU
- Path MTU Discovery говорит, что TCP-соединение может включать неявное согласование MTU через ICMP
Я не знаю о создании ICMP через API в Windows: когда-то был предложен такой API, и он был спорным, потому что люди утверждали, что упростит работу с программным обеспечением, которое реализует функции отказа в обслуживании, поток сообщений ICMP.
Нет, похоже, что он реализован: см., например, Winsock Programmer FAQ Примеры: Ping: Raw Sockets Method.
Итак, чтобы обнаружить MTU, создайте ping-пакеты с флагом "не фрагментировать".
Может быть, есть более простой API, чем я, я не знаю; но я надеюсь, что я дал вам понять базовый протокол [s].
Ответ 2
В дополнение ко всем предыдущим ответам, цитируя classic:
IPv4 и IPv6 определяют минимальный размер буфера повторной сборки
, минимальный размер дейтаграммы, который нам гарантирован, должен поддерживать. Для IPv4 это 576 байт. IPv6 повышает это до 1280 байт.
Это в значительной степени означает, что вы хотите ограничить размер вашей дейтаграммы до 576, если вы работаете в общедоступном Интернете, и вы контролируете только одну сторону обмена - что делает большинство стандартных протоколов UDP.
Также обратите внимание, что PMTU является динамическим свойством пути. Это одна из вещей, с которой работает TCP. Если вы не готовы повторить много логики последовательности, синхронизации и повторной передачи, используйте TCP для любой критической сети. Тест, тест, профиль, т.е. доказать, что TCP является вашим узким местом, только тогда рассмотрим UDP.
Ответ 3
Это интересная тема для меня. Возможно, некоторые практические результаты могут представлять интерес при доставке коротких данных UDP в реальном мире через Интернет через UDP и со скоростью передачи 1 пакет в секунду, данные продолжают появляться с минимальной потерей пакетов до примерно 2K. По этому и вы начинаете сталкиваться с проблемами, но регулярно мы поставляем пакеты с 1600 байтами без бедствия - это больше, чем мобильные сети GPRS, а также WAN по всему миру. При ~ 1K, если сигнал стабилен (его нет!), Вы получаете небольшую потерю пакетов.
Интересно, что это не нечетный пакет, а часто шквал пакетов в течение нескольких секунд, что, по-видимому, объясняется тем, что VoIP-вызовы иногда рушится.
Ответ 4
Ваш собственный MTU доступен в registry, но MTU на практике подходит к самому маленькому MTU на пути между вашим машины и места назначения. Его обе переменные и могут быть определены только эмпирически. Существует несколько RFC, показывающих, как их определить.
Локальная сеть может иметь очень большие значения MTU, поскольку сетевое оборудование обычно однородно или, по меньшей мере, централизованно администрируется.
Ответ 5
Для приложений UDP вы должны обрабатывать сквозной MTU самостоятельно, если хотите избежать фрагментации IP-адресов или потери пакетов. Рекомендуемый подход для любого приложения - стараться использовать PMTU для выбора максимальной датаграммы или отправлять дейтаграммы & lt; минимальный PMTU
https://tools.ietf.org/html/rfc5405#section-3.2
Рекомендации по использованию одноадресного UDP для разработчиков приложений "НЕ СЛЕДУЕТ отправлять дейтаграммы, превышающие PMTU, ДОЛЖНЫ обнаруживать PMTU или отправлять дейтаграммы & lt; минимум PMTU
Появится окно настроек и доступа к информации PMTU через интерфейс основных опций сокета:
Вы можете убедиться, что обнаружение PMTU включено через IP_MTU_DISCOVER, и вы можете прочитать MTU через IP_MTU.
https://docs.microsoft.com/en-us/windows/desktop/winsock/ipproto-ip-socket-options
Ответ 6
Здесь немного Windows PowerShell, который я написал, чтобы проверить наличие проблем с MTU. (Общая техника не слишком сложна для реализации на других языках программирования.) Многие брандмауэры и маршрутизаторы настроены так, чтобы отбрасывать все ICMP людьми, которые не знают ничего лучше. Определение MTU пути зависит от возможности получения сообщения ICMP Destination Unreachable с параметром Fragementation Needed в ответ на отправку пакета с параметром Don't Fragment. Устранение проблем фрагментации IPv4, MTU, MSS и PMTUD с помощью GRE и IPsec действительно хорошо объясняет, как работает обнаружение.
function Test-IPAddressOrName($ipAddressOrName)
{
$ipaddress = $null
$isValidIPAddressOrName = [ipaddress]::TryParse($ipAddressOrName, [ref] $ipaddress)
if ($isValidIPAddressOrName -eq $false)
{
$hasResolveDnsCommand = $null -ne (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)
if ($hasResolveDnsCommand -eq $true)
{
$dnsResult = Resolve-DnsName -DnsOnly -Name $ipAddressOrName -ErrorAction SilentlyContinue
$isValidIPAddressOrName = $null -ne $dnsResult
}
}
return $isValidIPAddressOrName
}
function Get-NameAndIPAddress($ipAddressOrName)
{
$hasResolveDnsCommand = $null -ne (Get-Command Resolve-DnsName -ErrorAction SilentlyContinue)
$ipAddress = $null
$validIPAddress = [ipaddress]::TryParse($ipAddressOrName, [ref] $ipAddress)
$nameAndIp = [PSCustomObject] @{ 'Name' = $null; 'IPAddress' = $null }
if ($validIPAddress -eq $false)
{
if ($hasResolveDnsCommand -eq $true)
{
$dnsResult = Resolve-DnsName -DnsOnly $ipAddressOrName -Type A -ErrorAction SilentlyContinue
if ($null -ne $dnsResult -and $dnsResult.QueryType -eq 'A')
{
$nameAndIp.Name = $dnsResult.Name
$nameAndIp.IPAddress = $dnsResult.IPAddress
}
else
{
Write-Error "The name $($ipAddressOrName) could not be resolved."
$nameAndIp = $null
}
}
else
{
Write-Warning "Resolve-DnsName not present. DNS resolution check skipped."
}
}
else
{
$nameAndIp.IPAddress = $ipAddress
if ($hasResolveDnsCommand -eq $true)
{
$dnsResult = Resolve-DnsName -DnsOnly $ipAddress -Type PTR -ErrorAction SilentlyContinue
if ($null -ne $dnsResult -and $dnsResult.QueryType -eq 'PTR')
{
$nameAndIp.Name = $dnsResult.NameHost
}
}
}
return $nameAndIp
}
<#
.Synopsis
Performs a series of pings (ICMP echo requests) with Don't Fragment specified to discover the path MTU (Maximum Transmission Unit).
.Description
Performs a series of pings with Don't Fragment specified to discover the path MTU (Maximum Transmission Unit). An ICMP echo request
is sent with a random payload with a payload length specified by the PayloadBytesMinimun. ICMP echo requests of increasing size are
sent until a ping response status other than Success is received. If the response status is PackeTooBig, the last successful packet
length is returned as a reliable MTU; otherwise, if the respone status is TimedOut, the same size packet is retried up to the number
of retries specified. If all of the retries have been exhausted with a response status of TimedOut, the last successful packet
length is returned as the assumed MTU.
.Parameter UseDefaultGateway
If UseDefaultGateway is specified the default gateway reported by the network interface is used as the destination host.
.Parameter DestinationHost
The IP Address or valid fully qualified DNS name of the destination host.
.Parameter InitialTimeout
The number of milliseconds to wait for an ICMP echo reply. Internally, this is doubled each time a retry occurs.
.Parameter Retries
The number of times to try the ping in the event that no reply is recieved before the timeout.
.Parameter PayloadBytesMinimum
The minimum number of bytes in the payload to use. The minimum MTU for IPv4 is 68 bytes; however, in practice, it extremely rare
to see an MTU size less than 576 bytes so the default value is 548 bytes (576 bytes total packet size minus an ICMP header of 28
bytes).
.Parameter PayloadBytesMaximum
The maximum number of bytes in the payload to use. An IPv4 MTU for jumbo frames is 9000 bytes. The default value is 8973 bytes (9001
bytes total packet size, which is 1 byte larger than the maximum IPv4 MTU for a jumbo frame, minus an ICMP header of 28 bytes).
.Example
Discover-PathMTU -UseDefaultGateway
.Example
Discover-PathMTU -DestinationHost '192.168.1.1'
.Example
Discover-PathMTU -DestinationHost 'www.google.com'
#>
function Discover-PathMtu
{
[CmdletBinding(SupportsShouldProcess = $false)]
param
(
[Parameter(Mandatory = $true, ParameterSetName = 'DefaultGateway')]
[switch] $UseDefaultGateway,
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ParameterSetName = 'IPAddressOrName')]
[ValidateScript({ Test-IPAddressOrName $_ })]
[string] $DestinationHost,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
[int] $InitialTimeout = 3000,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
[int] $Retries = 3,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
$PayloadBytesMinimum = 548,
[Parameter(ParameterSetName = 'IPAddressOrName')]
[Parameter(ParameterSetName = 'DefaultGateway')]
$PayloadBytesMaximum = 8973
)
begin
{
$ipConfiguration = Get-NetIPConfiguration -Detailed | ?{ $_.NetProfile.Ipv4Connectivity -eq 'Internet' -and $_.NetAdapter.Status -eq 'Up' } | Sort { $_.IPv4DefaultGateway.InterfaceMetric } | Select -First 1
$gatewayIPAddress = $ipConfiguration.IPv4DefaultGateway.NextHop
$pingOptions = New-Object System.Net.NetworkInformation.PingOptions
$pingOptions.DontFragment = $true
$pinger = New-Object System.Net.NetworkInformation.Ping
$rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
}
process
{
$pingIpAddress = $null
if ($UseDefaultGateway -eq $true)
{
$DestinationHost = $gatewayIPAddress
}
$nameAndIP = Get-NameAndIPAddress $DestinationHost
if ($null -ne $nameAndIP)
{
Write-Host "Performing Path MTU discovery for $($nameAndIP.Name) $($nameAndIP.IPAddress)..."
$pingReply = $null
$payloadLength = $PayloadBytesMinimum
$workingPingTimeout = $InitialTimeout
do
{
$payloadLength++
# Use a random payload to prevent compression in the path from potentially causing a false MTU report.
[byte[]] $payloadBuffer = (,0x00 * $payloadLength)
$rng.GetBytes($payloadBuffer)
$pingCount = 1
do
{
$pingReply = $pinger.Send($nameAndIP.IPAddress, $workingPingTimeout, $payloadBuffer, $pingOptions)
if ($pingReply.Status -notin 'Success', 'PacketTooBig', 'TimedOut')
{
Write-Warning "An unexpected ping reply status, $($pingReply.Status), was received in $($pingReply.RoundtripTime) milliseconds on attempt $($pingCount)."
}
elseif ($pingReply.Status -eq 'TimedOut')
{
Write-Warning "The ping request timed out while testing a packet of size $($payloadLength + 28) using a timeout value of $($workingPingTimeout) milliseconds on attempt $($pingCount)."
$workingPingTimeout = $workingPingTimeout * 2
}
else
{
Write-Verbose "Testing packet of size $($payloadLength + 28). The reply was $($pingReply.Status) and was received in $($pingReply.RoundtripTime) milliseconds on attempt $($pingCount)."
$workingPingTimeout = $InitialTimeout
}
Sleep -Milliseconds 10
$pingCount++
} while ($pingReply.Status -eq 'TimedOut' -and $pingCount -le $Retries)
} while ($payloadLength -lt $PayloadBytesMaximum -and $pingReply -ne $null -and $pingReply.Status -eq 'Success')
if ($pingReply.Status -eq 'PacketTooBig')
{
Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27)."
}
elseif ($pingReply.Status -eq 'TimedOut')
{
Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27), but may not be reliable because the packet appears to have been discarded."
}
else
{
Write-Host "Reported IPv4 MTU is $($ipConfiguration.NetIPv4Interface.NlMtu). The discovered IPv4 MTU is $($payloadLength + 27), but may not be reliable, due to an unexpected ping reply status."
}
return $payloadLength + 27
}
else
{
Write-Error "The name $($DestinationHost) could not be resolved. No Path MTU discovery will be performed."
}
}
end
{
if ($null -ne $pinger)
{
$pinger.Dispose()
}
if ($null -ne $rng)
{
$rng.Dispose()
}
}
}