📄 udtsocket.cs
字号:
//#define UDT_TRACE
//#define UDT_FULLTCP
//#define NO_UDT_CONNECTION
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using System.Security;
namespace Helper.Net.UDT
{
/// <summary>
/// This class is a wrapper class around the UDT project ( http://udt.sf.net )
/// </summary>
public sealed class UDTSocket
{
#region API
[DllImport("transport.dll", EntryPoint = "UDTSocket"), SuppressUnmanagedCodeSecurity()]
private static extern int API_UDTSocket(int af, int type, int protocol);
[DllImport("transport.dll", EntryPoint = "UDTConnect"), SuppressUnmanagedCodeSecurity()]
private static extern int API_UDTConnect(int handle, byte[] name, int namelen);
[DllImport("transport.dll", EntryPoint = "UDTBind"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Bind(int handle, byte[] name, int namelen);
[DllImport("transport.dll", EntryPoint = "UDTListen"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Listen(int handle, int backlog);
[DllImport("transport.dll", EntryPoint = "UDTAccept"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Accept(int handle, byte[] name, out int namelen);
[DllImport("transport.dll", EntryPoint = "UDTClose"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Close(int handle);
[DllImport("transport.dll", EntryPoint = "UDTShutdown"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Shutdown(int handle, int how);
[DllImport("transport.dll", EntryPoint = "UDTSend"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Send(int handle, byte[] buffer, int len, int flags);
[DllImport("transport.dll", EntryPoint = "UDTRecv"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Receive(int handle, byte[] buffer, int offset, int len, int flags);
[DllImport("transport.dll", EntryPoint = "UDTSendmsg"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Sendmsg(int handle, byte[] buffer, int len, int ttl, bool inorder);
[DllImport("transport.dll", EntryPoint = "UDTRecvmsg"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Recvmsg(int handle, byte[] buffer, int offset, int len);
[DllImport("transport.dll", EntryPoint = "UDTSelect"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Select([In] int ignoredParameter, [In, Out] IntPtr[] readfds, [In, Out] IntPtr[] writefds, [In, Out] IntPtr[] exceptfds, [In] ref TimeValue timeout);
[DllImport("transport.dll", EntryPoint = "UDTSetsockopt"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Setsockopt(int handle, int level, UDTSocketOptionName option, ref object optionValue, int optlen);
[DllImport("transport.dll", EntryPoint = "UDTGetsockopt"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Getsockopt(int handle, int level, UDTSocketOptionName option, ref object optionValue, int optlen);
[DllImport("transport.dll", EntryPoint = "UDTGetpeername"), SuppressUnmanagedCodeSecurity()]
private static extern int API_Getpeername(int handle, byte[] name, out int namelen);
[DllImport("transport.dll", EntryPoint = "UDTGetlasterrorCode"), SuppressUnmanagedCodeSecurity()]
private static extern int API_GetLastErrorCode();
[DllImport("transport.dll", EntryPoint = "UDTGetlasterrorMessage"), SuppressUnmanagedCodeSecurity()]
private static extern string API_GetLastErrorMessage();
[DllImport("transport.dll", EntryPoint = "UDTIsOnAccept"), SuppressUnmanagedCodeSecurity()]
private static extern bool API_IsOnAccept(int handle);
[DllImport("transport.dll", EntryPoint = "UDTIsOnRead"), SuppressUnmanagedCodeSecurity()]
private static extern bool API_IsOnRead(int handle);
[DllImport("transport.dll", EntryPoint = "UDTIsOnWrite"), SuppressUnmanagedCodeSecurity()]
private static extern bool API_IsOnWrite(int handle);
[DllImport("transport.dll", EntryPoint = "UDTIsOnError"), SuppressUnmanagedCodeSecurity()]
private static extern bool API_IsOnError(int handle);
[DllImport("transport.dll", EntryPoint = "UDTIsConnected"), SuppressUnmanagedCodeSecurity()]
private static extern bool API_IsConnected(int handle);
[DllImport("transport.dll", EntryPoint = "UDTSelect"), SuppressUnmanagedCodeSecurity()]
private static extern int API_UDTSelect(int[] readfds, int readCount, int[] writefds, int writeCount, int[] exceptfds, int timeoutMicroseconds);
[DllImport("transport.dll", EntryPoint = "UDTWaitForEvent"), SuppressUnmanagedCodeSecurity()]
private static extern void API_WaitForEvent();
//[DllImport("transport.dll", EntryPoint = "UDTGetoverlappedresult")]
//private static extern bool API_Getoverlappedresult(int handle, int ioHandle, ref int progress, bool wait);
private static int UDT_ERROR = -1;
private static int UDT_INVALID_SOCK = -1;
[StructLayout(LayoutKind.Sequential)]
internal struct TimeValue
{
public int Seconds;
public int Microseconds;
}
[StructLayout(LayoutKind.Sequential)]
internal struct UDTLinger
{
internal short OnOff;
internal short Time;
}
#endregion
#region API - Asynchronous
[DllImport("transport.dll", EntryPoint = "UDTSetAsynchronous"), SuppressUnmanagedCodeSecurity()]
private static extern int API_SetAsynchronous(int handle, bool isAsynchronous);
[DllImport("transport.dll", EntryPoint = "UDTSetEndSendCallback"), SuppressUnmanagedCodeSecurity()]
private static extern int API_SetUDTEndSendCallback([MarshalAs(UnmanagedType.FunctionPtr)]EndOperationHandler callback);
[DllImport("transport.dll", EntryPoint = "UDTBeginSend"), SuppressUnmanagedCodeSecurity()]
private static extern int API_BeginSend(int handle, byte[] buffer, int len, int flags, IntPtr context);
#endregion
#region Variables
private static Thread _udtThreadProcessing;
internal static CommandProcessor.CommandProcessor _processor = new Helper.CommandProcessor.CommandProcessor("UDT");
//---- Asynch send & receive
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
private delegate void EndOperationHandler(IntPtr pointer);
// This method is called by UDT once a send is done
static private EndOperationHandler udtEndSendCallback;
// This method is called by UDT once a receive is done
//static private EndOperationHandler udtEndReceiveCallback;
//---- Generic information
private SocketType _socketType;
//---- Tags
public object Tag;
#if UDT_FULLTCP
private System.Net.Sockets.Socket _tcpSocket;
#else
//---- UDT
// Socket Handler
private int _handle = -1;
// EndPoints
private IPEndPoint _remoteEndPoint;
private IPEndPoint _localEndPoint;
#endif
#endregion
#region Static
/// <summary>
/// Initialize the background processing for all the UDT threads.
/// </summary>
static UDTSocket()
{
#if !NO_UDT_CONNECTION
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
// Set the callbacks
udtEndSendCallback = new EndOperationHandler(UDTEndSendCallback);
GC.KeepAlive(udtEndSendCallback);
API_SetUDTEndSendCallback(udtEndSendCallback);
// Start the processor
_processor.Start();
// Main select thread
_udtThreadProcessing = new Thread(new ThreadStart(UDTThreadProcessing));
_udtThreadProcessing.IsBackground = true;
_udtThreadProcessing.Name = "UDTThread Select Processing";
_udtThreadProcessing.Start();
#endif
}
/// <summary>
/// Stop all the processing for all the UDT sockets.
/// </summary>
static public void ShutDownUDT()
{
#if !NO_UDT_CONNECTION
if (_processor != null)
lock (_processor)
{
if (_udtThreadProcessing != null)
{
_udtThreadProcessing.Abort();
_udtThreadProcessing = null;
}
if (_processor != null)
{
_processor.Stop();
_processor = null;
}
}
#endif
}
static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
ShutDownUDT();
}
#endregion
#region Constructors
#if !UDT_FULLTCP
/// <summary>
/// This method is used only by the UDT "accept" method in order
/// to create a new socket.
/// </summary>
private UDTSocket(int handle, SocketType socketType, IPEndPoint remoteEndPoint, IPEndPoint localEndPoint)
{
_socketType = socketType;
_handle = handle;
_remoteEndPoint = remoteEndPoint;
_localEndPoint = localEndPoint;
IsAsynchronous = true;
/*
if ( socketType == SocketType.Stream )
{
//UDT::setsockopt(client, 0, UDT_MSS, new int(1052), sizeof(int));
int MTU = 1052;
API_Setsockopt(_handle, 0, UDTOption.UDT_MSS, ref MTU, Marshal.SizeOf(MTU));
}
*/
//int Disconnected = 60000;
//API_Setsockopt(_handle, 0, UDTOption.UDT_LINGER, ref Disconnected, Marshal.SizeOf(Disconnected));
}
#else
public UDTSocket(System.Net.Sockets.Socket tcpSocket)
{
_tcpSocket = tcpSocket;
}
#endif
public UDTSocket(AddressFamily addressFamily)
{
#if UDT_FULLTCP
_tcpSocket = new System.Net.Sockets.Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
#else
_socketType = SocketType.Stream;
_handle = API_UDTSocket((int)addressFamily, (int)_socketType, (int)0);
IsAsynchronous = true;
/*
if ( socketType == SocketType.Stream )
{
//UDT::setsockopt(client, 0, UDT_MSS, new int(1052), sizeof(int));
int MTU = 1052;
API_Setsockopt(_handle, 0, UDTOption.UDT_MSS, ref MTU, Marshal.SizeOf(MTU));
}
*/
#endif
}
#endregion
#region Connect
public void Connect(EndPoint remoteEP)
{
#if !NO_UDT_CONNECTION
//---- Tracing
UDTTrace("UDTSocket[" + Handle + "]-Connect:" + remoteEP.ToString());
#if UDT_FULLTCP
_tcpSocket.Connect(remoteEP);
#else
//---- UDT
SocketAddress address = ((IPEndPoint)remoteEP).Serialize();
byte[] addressBuffer = new byte[address.Size];
for (int index = 0; index < address.Size; index++)
addressBuffer[index] = address[index];
if (UDT_ERROR == API_UDTConnect(_handle, addressBuffer, address.Size))
throw new UDTSocketException(); // Cannot connect
#endif
#else
throw new UDTSocketException(); // Cannot connect
#endif
}
#endregion
#region Select
static public void Select(int[] readHandles, int[] writeHandles, int[] exceptionHandles, int timeOutMicroSeconds)
{
if (UDT_ERROR == API_UDTSelect(readHandles, readHandles.Length, writeHandles, writeHandles.Length, exceptionHandles, timeOutMicroSeconds))
throw new UDTSocketException(); // Cannot connect
}
#endregion
#region Bind
public void Bind(EndPoint localEP)
{
_localEndPoint = (IPEndPoint)localEP;
// Tracing
UDTTrace("Bind[" + Handle + "]" + localEP.ToString());
#if UDT_FULLTCP
_tcpSocket.Bind(localEP);
#else
//---- UDT
SocketAddress address = ((IPEndPoint)localEP).Serialize();
byte[] addressBuffer = new byte[address.Size];
for (int index = 0; index < address.Size; index++)
addressBuffer[index] = address[index];
if (UDT_ERROR == API_Bind(_handle, addressBuffer, address.Size))
throw new UDTSocketException();
#endif
}
#endregion
#region Listen
public void Listen(int backlog)
{
#if UDT_FULLTCP
_tcpSocket.Listen(backlog);
#else
//---- UDT
if (UDT_ERROR == API_Listen(_handle, backlog))
throw new UDTSocketException();
#endif
}
#endregion
#region Accept
public UDTSocket Accept()
{
#if UDT_FULLTCP
System.Net.Sockets.Socket newSocket = _tcpSocket.Accept();
UDTSocket newUDTSocket = new UDTSocket(newSocket);
// Tracing
UDTTrace("UDTSocket[" + _tcpSocket.Handle + ", new:" + newSocket.Handle + "]-Accept:" + newSocket.RemoteEndPoint.ToString());
return newUDTSocket;
#else
//---- UDT
EndPoint localEP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
SocketAddress address = ((IPEndPoint)localEP).Serialize();
byte[] addressBuffer = new byte[address.Size];
for (int index = 0; index < address.Size; index++)
addressBuffer[index] = address[index];
//---- Accept
int size = 0;
int newHandle = API_Accept(_handle, addressBuffer, out size);
if (UDT_INVALID_SOCK == newHandle) // UDT::INVALID_SOCK
{
throw new UDTSocketException(API_GetLastErrorCode(),
API_GetLastErrorMessage());
}
//---- Get the IP+port of the peer socket (RemoteEndPoint)
for (int index = 0; index < address.Size; index++)
address[index] = addressBuffer[index];
IPEndPoint remoteEndPoint;
if (address.Family == AddressFamily.InterNetwork)
remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
else
remoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
remoteEndPoint = (IPEndPoint)(remoteEndPoint.Create(address));
//---- Get the IP+port of the socket (LocalEndPoint)
size = address.Size;
if (UDT_ERROR == API_Getpeername(newHandle, addressBuffer, out size))
{
throw new UDTSocketException(API_GetLastErrorCode(),
API_GetLastErrorMessage());
}
IPEndPoint localEndPoint;
if (address.Family == AddressFamily.InterNetwork)
localEndPoint = new IPEndPoint(IPAddress.Any, 0);
else
localEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
localEndPoint = (IPEndPoint)(localEndPoint.Create(address));
//---- Tracing
UDTTrace("UDTSocket[" + _handle + ", new:" + newHandle + "]-Accept:" + remoteEndPoint.ToString());
//---- Return the new socket
return new UDTSocket(newHandle, _socketType, remoteEndPoint, localEndPoint);
#endif
}
#endregion
#region Close
public void Close()
{
#if UDT_FULLTCP
_tcpSocket.Close();
#else
//---- UDT
API_Close(_handle);
_handle = -1;
#endif
}
#endregion
#region Shutdown
public void Shutdown(SocketShutdown how)
{
#if UDT_FULLTCP
_tcpSocket.Shutdown(how);
#else
API_Shutdown(_handle, (int)how);
#endif
}
#endregion
#region Send
public int Send(byte[] buffer)
{
return Send(buffer, SocketFlags.None);
}
public int Send(byte[] buffer, SocketFlags socketFlags)
{
return Send(buffer, buffer.Length, socketFlags);
}
public int Send(byte[] buffer, int length, SocketFlags socketFlags)
{
UDTTrace("UDTSocket[" + Handle + "]-Send:size=" + length);
#if UDT_FULLTCP
return _tcpSocket.Send(buffer, length, socketFlags);
#else
//---- UDT
if (_socketType == SocketType.Dgram)
return API_Sendmsg(_handle, buffer, length,
-1, // Infinite time out
true); // Messages are sent and received in the same order
else
{
return API_Send(_handle, buffer, length, (int)socketFlags);
}
#endif
}
public int Send(byte[] buffer, int offset, int length, SocketFlags socketFlags)
{
#if UDT_FULLTCP
return _tcpSocket.Send(buffer, offset, length, socketFlags);
#else
//---- UDT
if (offset < 1)
return Send(buffer, length, socketFlags);
byte[] newBuffer = new byte[buffer.Length - offset];
Array.Copy(buffer, offset, newBuffer, 0, buffer.Length - offset);
return Send(newBuffer, length, socketFlags);
#endif
}
#endregion
#region Receive
public int Receive(byte[] buffer, int length, SocketFlags socketFlags)
{
return Receive(buffer, 0, length, socketFlags);
}
public int Receive(byte[] buffer, int offset, int length, SocketFlags socketFlags)
{
#if UDT_FULLTCP
int size = _tcpSocket.Receive(buffer, offset, length, socketFlags);
UDTTrace("UDTSocket[" + Handle + "]-Receive:size=" + size);
return size;
#else
//---- UDT
try
{
if (_socketType == SocketType.Dgram)
return API_Recvmsg(_handle, buffer, offset, length);
else
{
int size = API_Receive(_handle, buffer, offset, length, (int)socketFlags);
UDTTrace("UDTSocket[" + _handle + "]-Receive:size=" + size);
if (size < 0) // Like TCP
return 0;
return size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -