⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udtsocket.cs

📁 rudp可靠保障得udp传输
💻 CS
📖 第 1 页 / 共 2 页
字号:
//#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 + -