📄 rudpsocket.cs
字号:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Helper.Threading.Collections;
namespace Helper.Net.RUDP
{
#region RUDPSocketStatus
internal enum RUDPSocketStatus
{
Connecting, // During the connection phase
Connected, // We are connected
Closing, // During the closing phase
ClosingACKed, // When the tear down message has been ACKed
Closed, // The connection is closed / It is the default status
Accepting
}
#endregion
#region RUDPSocketError
/// <summary>
/// For more information about socket errors :
/// http://support.microsoft.com/default.aspx?scid=kb;en-us;819124
/// </summary>
public enum RUDPSocketError
{
// Summary:
// An unspecified System.Net.Sockets.ServerSocket error has occurred.
SocketError = -1,
//
// Summary:
// The System.Net.Sockets.ServerSocket operation succeeded.
Success = 0,
//
// Summary:
// The overlapped operation was aborted due to the closure of the System.Net.Sockets.ServerSocket.
//OperationAborted = 995,
//
// Summary:
// The application has initiated an overlapped operation that cannot be completed
// immediately.
//IOPending = 997,
//
// Summary:
// A blocking System.Net.Sockets.ServerSocket call was canceled.
//Interrupted = 10004,
//
// Summary:
// An attempt was made to access a System.Net.Sockets.ServerSocket in a way that is
// forbidden by its access permissions.
//AccessDenied = 10013,
//
// Summary:
// An invalid pointer address was detected by the underlying socket provider.
//Fault = 10014,
//
// Summary:
// An invalid argument was supplied to a System.Net.Sockets.ServerSocket member.
//InvalidArgument = 10022,
//
// Summary:
// There are too many open sockets in the underlying socket provider.
//TooManyOpenSockets = 10024,
//
// Summary:
// An operation on a nonblocking socket cannot be completed immediately.
//WouldBlock = 10035,
//
// Summary:
// A blocking operation is in progress.
InProgress = 10036,
//
// Summary:
// The nonblocking System.Net.Sockets.ServerSocket already has an operation in progress.
AlreadyInProgress = 10037,
//
// Summary:
// A System.Net.Sockets.ServerSocket operation was attempted on a non-socket.
//NotSocket = 10038,
//
// Summary:
// A required address was omitted from an operation on a System.Net.Sockets.ServerSocket.
//DestinationAddressRequired = 10039,
//
// Summary:
// The datagram is too long.
//MessageSize = 10040,
//
// Summary:
// The protocol type is incorrect for this System.Net.Sockets.ServerSocket.
//ProtocolType = 10041,
//
// Summary:
// An unknown, invalid, or unsupported option or level was used with a System.Net.Sockets.ServerSocket.
//ProtocolOption = 10042,
//
// Summary:
// The protocol is not implemented or has not been configured.
//ProtocolNotSupported = 10043,
//
// Summary:
// The support for the specified socket type does not exist in this address
// family.
//SocketNotSupported = 10044,
//
// Summary:
// The address family is not supported by the protocol family.
//OperationNotSupported = 10045,
//
// Summary:
// The protocol family is not implemented or has not been configured.
//ProtocolFamilyNotSupported = 10046,
//
// Summary:
// The address is incompatible with the requested protocol.
//AddressFamilyNotSupported = 10047,
//
// Summary:
// Only one use of an address is normally permitted.
//AddressAlreadyInUse = 10048,
//
// Summary:
// The selected address is valid in this context.
//AddressNotAvailable = 10049,
//
// Summary:
// The network is not available.
NetworkDown = 10050,
//
// Summary:
// No route to the remote host exists.
NetworkUnreachable = 10051,
//
// Summary:
// The application tried to set System.Net.Sockets.SocketOptionName.KeepAlive
// on a connection that has already timed out.
NetworkReset = 10052,
//
// Summary:
// The connection was aborted by the .NET Framework or the underlying socket
// provider.
//ConnectionAborted = 10053,
//
// Summary:
// The connection was reset by the remote peer.
ConnectionReset = 10054,
//
// Summary:
// No free buffer space is available for a System.Net.Sockets.ServerSocket operation.
NoBufferSpaceAvailable = 10055,
//
// Summary:
// The System.Net.Sockets.ServerSocket is already connected.
IsConnected = 10056,
//
// Summary:
// The application tried to send or receive data, and the System.Net.Sockets.ServerSocket
// is not connected.
NotConnected = 10057,
//
// Summary:
// A request to send or receive data was disallowed because the System.Net.Sockets.ServerSocket
// has already been closed.
Shutdown = 10058,
//
// Summary:
// The connection attempt timed out, or the connected host has failed to respond.
TimedOut = 10060,
//
// Summary:
// The remote host is actively refusing a connection.
ConnectionRefused = 10061,
//
// Summary:
// The operation failed because the remote host is down.
HostDown = 10064,
//
// Summary:
// There is no network route to the specified host.
HostUnreachable = 10065,
//
// Summary:
// Too many processes are using the underlying socket provider.
ProcessLimit = 10067,
//
// Summary:
// The network subsystem is unavailable.
SystemNotReady = 10091,
//
// Summary:
// The version of the underlying socket provider is out of range.
//VersionNotSupported = 10092,
//
// Summary:
// The underlying socket provider has not been initialized.
NotInitialized = 10093,
//
// Summary:
// A graceful shutdown is in progress.
Disconnecting = 10101,
//
// Summary:
// The specified class was not found.
//TypeNotFound = 10109,
//
// Summary:
// No such host is known. The name is not an official host name or alias.
HostNotFound = 11001,
//
// Summary:
// The name of the host could not be resolved. Try again later.
//TryAgain = 11002,
//
// Summary:
// The error is unrecoverable or the requested database cannot be located.
//NoRecovery = 11003,
//
// Summary:
// The requested name or IP address was not found on the name server.
NoData = 11004,
}
#endregion
#region RUDPSocketException
sealed public class RUDPSocketException : Exception
{
public RUDPSocketError Error;
public RUDPSocketException(RUDPSocketError error)
{
Error = error;
}
}
#endregion
#region RUDPSocketNetworkInformation
sealed public class RUDPSocketNetworkInformation
{
#region Variables
private RUDPSocket _rudp;
#endregion
#region Constructor
internal RUDPSocketNetworkInformation(RUDPSocket rudp)
{
_rudp = rudp;
}
#endregion
#region Properties
public int PathMTU
{
get
{
return _rudp._mtu;
}
}
public double SendCongestionWindow
{
get
{
return _rudp._controlWindow._cwnd;
}
}
public double RTT
{
get
{
return _rudp._rtt;
}
}
public double RTO
{
get
{
return _rudp._rto;
}
}
/// <summary>
/// Estimated Bandwidth in Bytes/Milli-seconds
/// </summary>
public long BandWidth
{
get
{
return _rudp._bandwidth;
}
}
#endregion
}
#endregion
#region RUDPCongestionControl
public enum RUDPCongestionControl
{
TCPReno,
TCPBIC,
TCPCUBIC,
UDT,
Simple01
}
#endregion
sealed public class RUDPSocket
{
#region Variables
//---- Global
static internal int LockTimeOut = -1;
static internal int DefaultConnectionTimeOut = 60000;
static internal int LastHandle = 0;
//---- ServerSocket data
internal PhysicalSocket _physical;
internal IPEndPoint _remoteEndPoint;
internal bool _isRendezVousMode = false;
//---- State of the socket
internal RUDPSocketStatus _status = RUDPSocketStatus.Closed;
internal bool _isShutingDown = false;
//---- An internal handle
internal int _handle;
//----- Asynchronous call datas
internal RUDPAcceptIAsyncResult _asyncResultAccept;
internal RUDPConnectIAsyncResult _asyncResultConnect;
internal RUDPReceiveIAsyncResult _asyncResultReceive;
//----- Identify a byte in the flow (like TCP)
internal long _sequence = 0;
//---- List of outgoing and ingoing packets
internal ReaderWriterLock _sendingPacketsLock = new ReaderWriterLock();
internal List<RUDPOutgoingPacket> _sendingPackets = new List<RUDPOutgoingPacket>();
// incoming packets
internal Object _incomingPacketsLock = new Object();
internal SortedList _incomingPackets = new SortedList();
internal LockFreeQueue<RUDPIngoingPacket> _incomingNonReliablePackets = new LockFreeQueue<RUDPIngoingPacket>();
//---- List of incoming connections sockets
internal List<RUDPSocket> _acceptedRUDPSockets = new List<RUDPSocket>();
//---- List of outgoing and ingoing messages
internal int _ougoingPacketId;
internal int _incomingPacketId;
//---- Receive / Send size
internal int _receiveSize = 100 * 1024;
internal int _sendSize = 100 * 1024;
//---- ACKs management
internal SACKWindow _sackWindow;
// Last time an ACK has been sended
internal long _lastACKSendTS = -1;
//---- MTU
internal bool _usePMTUDiscovery = true;
internal PMTUDiscovery _pmtuDiscovery;
internal int _mtu = -1;
//---- Time Stamp : Last time we send a packet
internal long _lastSendTS;
//---- Time Stamp : for bandwidth calculation
internal long _lastBandwidthTS;
internal long _bandwidthResponse01TS;
internal long _bandwidth; // byte / ms
//---- RTT & Time outs
// RTT (Round Trip Time: time needed to send a message and receive its ACK)
internal double _rtt;
// RTO (Retransmission Time Out)
internal double _rto;
// Delta RTT (RTT difference)
internal double _deltaRtt;
// STO (send Time Out)
internal long _sto;
//---- Windows
internal AbstractWindow _controlWindow;
//---- Some statistics
private RUDPSocketNetworkInformation _networkInformation;
#if STATISTICS
internal int Stats_ReceivedMessagesCount = 0;
internal int Stats_SendedMessagesCount = 0;
internal int Stats_ResendedMessagesCount = 0;
internal int Stats_SendedACKCount = 0;
internal int Stats_LastQueuedSendedACKId = 0;
internal int Stats_LastSendedACKId = 0;
internal int Stats_ReceivedACKCount = 0;
internal int Stats_LastReceivedACKId = 0;
#endif
#endregion
#region Constructor
public RUDPSocket()
: this(RUDPCongestionControl.TCPReno)
{
}
public RUDPSocket(RUDPCongestionControl congestionControl)
{
switch (congestionControl)
{
case RUDPCongestionControl.TCPReno:
_controlWindow = new Helper.Net.RUDP.Reno.CongestionWindow(this);
break;
case RUDPCongestionControl.TCPBIC:
_controlWindow = new Helper.Net.RUDP.BIC.CongestionWindow(this);
break;
case RUDPCongestionControl.TCPCUBIC:
_controlWindow = new Helper.Net.RUDP.CUBIC.CongestionWindow(this);
break;
case RUDPCongestionControl.UDT:
_controlWindow = new Helper.Net.RUDP.UDT.CongestionWindow(this);
break;
case RUDPCongestionControl.Simple01:
_controlWindow = new Helper.Net.RUDP.Simple01.CongestionWindow(this);
break;
}
//---- Reset
Reset(RUDPSocketStatus.Closed);
//---- Update handle
_handle = LastHandle;
LastHandle++;
//---- Setup network information
_networkInformation = new RUDPSocketNetworkInformation(this);
}
internal void Reset(RUDPSocketStatus status)
{
RUDPStack.Trace("RESET PeerInformation");
//---- Reset all
_status = status;
_ougoingPacketId = -1;
_incomingPacketId = -1;
_sequence = 0;
_lastSendTS = 0;
_lastACKSendTS = -1;
_lastBandwidthTS = 0;
_bandwidthResponse01TS = 0;
_bandwidth = 0;
_sendingPacketsLock.AcquireWriterLock(RUDPSocket.LockTimeOut);
for (int index = 0; index < _sendingPackets.Count; index++)
RUDPStack.ReleaseOutgoingPacket(_sendingPackets[index]);
_sendingPackets.Clear();
_sendingPacketsLock.ReleaseWriterLock();
lock (_incomingPacketsLock)
_incomingPackets.Clear();
_incomingNonReliablePackets.Clear();
_sackWindow = new SACKWindow();
_pmtuDiscovery = new PMTUDiscovery(this);
_controlWindow.Reset();
}
#endregion
#region Bind
public void Bind(IPEndPoint endPoint)
{
// Get the associated physical socket
_physical = RUDPStack.GetInstance(endPoint);
}
private void AutomaticBind()
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
Bind(endPoint);
}
#endregion
#region Listen
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -