我一直在寻找如何增加 UDP 缓冲区,但没有解决方案。
我有某种通过 UDP JPEG 图像发送的网络摄像头。这些由 1024 字节的数据报包中的 cam(无 MTU 分段)划分。当图像大小接近 65K 时,图像会因为丢包而出错。我认为这是因为 UDP 传输提供程序的最大消息大小为 65527(0xfff7),您可以在 Windows SDK 中使用 SpOrder.exe 看到。
我尝试使用“Ws2_32.dll”中的函数 WSCUpdateProvider 更改此大小。我调用 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);
}