Я долго искал, как я могу увеличить буфер UDP без решения.
У меня есть какая-то веб-камера, которая передает UDP-изображения JPEG. Они делятся на кулачок (без фрагментации MTU) в пакетах дейтаграмм размером 1024 байта. Когда размер изображения приближается к 65К, изображение становится ошибочным из-за потерянных пакетов. Я думаю, что это связано с максимальным размером сообщения 65527 (0xfff7) транспортного провайдера UDP, который вы можете увидеть с помощью SpOrder.exe в Windows SDK.
Я попытался изменить этот размер с помощью функции WSCUpdateProvider из «Ws2_32.dll». Я вызвал WSCEnumProtocols для получения информации о транспортном провайдере UDP и WSCGetProviderPath, поскольку она также необходима, и я получаю нужную информацию, но когда я вызываю WSCUpdateProvider (независимо от того, какая информация предоставляется) с административными правами, я всегда получаю ошибку: 11003 (WSANO_RECOVERY ).
Есть какой-то трюк, который я пропустил или что-то? У меня нет прав для вызова этой функции? Нужно ли мне писать свой собственный транспортный провайдер UDP или есть другое решение?
Вот мой код в C #:
private void ConfigUDP(uint p)
{
Int32 protocol = 17;
WSAPROTOCOL_INFO[] info = null;
UInt32 len = 0;
Int32 err = 0;
NativeMethods.WSCEnumProtocols(ref protocol, info, ref len, ref err);
info = new WSAPROTOCOL_INFO[len/Marshal.SizeOf(typeof(WSAPROTOCOL_INFO))];
Int32 ret = NativeMethods.WSCEnumProtocols(ref protocol, info, ref len, ref err);
for (int i = 0; i < ret; i++)
{
if (info[i].iProtocol != 17)
{
continue;
}
Int32 pLen = 255;
StringBuilder path = new StringBuilder(pLen);
NativeMethods.WSCGetProviderPath(ref info[i].ProviderId, path, ref pLen, ref err);
WSAPROTOCOL_INFO[] newInfo = new WSAPROTOCOL_INFO[1];
Array.Copy(info, i, newInfo, 0, 1);
//newInfo[0].dwMessageSize = (UInt32) p;
int rs = NativeMethods.WSCUpdateProvider(ref info[i].ProviderId, ref path, newInfo, 1, ref err);
Console.WriteLine(new Win32Exception(Marshal.GetLastWin32Error()).Message);
Console.WriteLine(new Win32Exception(err).Message);
}
ret = NativeMethods.WSCEnumProtocols(ref protocol, info, ref len, ref err);
for (int i = 0; i < ret; i++)
{
Console.WriteLine(info[i].dwMessageSize);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct WSAPROTOCOLCHAIN
{
public Int32 ChainLen; /* the length of the chain, */
/* length = 0 means layered protocol, */
/* length = 1 means base protocol, */
/* length > 1 means protocol chain */
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U4, SizeConst = 7)] /* a list of dwCatalogEntryIds */
public UInt32[] ChainEntries;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct WSAPROTOCOL_INFO
{
public UInt32 dwServiceFlags1;
public UInt32 dwServiceFlags2;
public UInt32 dwServiceFlags3;
public UInt32 dwServiceFlags4;
public UInt32 dwProviderFlags;
public Guid ProviderId;
public UInt32 dwCatalogEntryId;
public WSAPROTOCOLCHAIN ProtocolChain;
public Int32 iVersion;
public Int32 iAddressFamily;
public Int32 iMaxSockAddr;
public Int32 iMinSockAddr;
public Int32 iSocketType;
public Int32 iProtocol;
public Int32 iProtocolMaxOffset;
public Int32 iNetworkByteOrder;
public Int32 iSecurityScheme;
public UInt32 dwMessageSize;
public UInt32 dwProviderReserved;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szProtocol;
}
internal class NativeMethods
{
[DllImport("Ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern Int32 WSCUpdateProvider(ref Guid lpProviderId, ref StringBuilder lpszProviderDllPath, WSAPROTOCOL_INFO[] lpProtocolInfoList, UInt32 dwNumberOfEntries, ref Int32 lpErrno);
[DllImport("Ws2_32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
internal static extern Int32 WSCEnumProtocols(ref Int32 lpiProtocols, [Out] WSAPROTOCOL_INFO[] lpProtocolBuffer, ref UInt32 lpdwBufferLength, ref Int32 lpErrno);
//Overloaded so I can pass null for iProtocols
[DllImport("Ws2_32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
internal static extern Int32 WSCEnumProtocols(IntPtr lpiProtocols, [Out] WSAPROTOCOL_INFO[] lpProtocolBuffer, ref UInt32 lpdwBufferLength, ref Int32 lpErrno);
[DllImport("Ws2_32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
internal static extern Int32 WSCGetProviderPath(ref Guid lpProviderId, [Out] StringBuilder lpszProviderDllPath, ref Int32 lpProviderDllPathLen, ref Int32 lpErrno);
}
Задача ещё не решена.
Других решений пока нет …