.NET *ASync Socket API

Incomplete, do not use (/d:Framework_4_0) in production.
This commit is contained in:
mark 2010-12-19 23:35:09 +00:00
parent 17b1cccc5e
commit 0afa707b24
2 changed files with 323 additions and 126 deletions

View file

@ -66,7 +66,7 @@ namespace Server.Network
#if Framework_4_0
m_EventArgs = new SocketAsyncEventArgs();
m_EventArgs.Completed += new EventHandler<SocketAsyncEventArgs>( Accept_Completion );
ThreadPool.QueueUserWorkItem( delegate { Accept_Start(); } );
Accept_Start();
#else
m_OnAccept = new AsyncCallback( OnAccept );
try {

View file

@ -50,7 +50,13 @@ namespace Server.Network {
private SendQueue m_SendQueue;
private bool m_Seeded;
private bool m_Running;
#if Framework_4_0
private SocketAsyncEventArgs m_ReceiveEventArgs, m_SendEventArgs;
#else
private AsyncCallback m_OnReceive, m_OnSend;
#endif
private MessagePump m_MessagePump;
private ServerInfo[] m_ServerInfo;
private IAccount m_Account;
@ -103,48 +109,6 @@ namespace Server.Network {
private AsyncState m_AsyncState;
private object m_AsyncLock = new object();
public static void Pause() {
m_Paused = true;
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
lock ( ns.m_AsyncLock ) {
ns.m_AsyncState |= AsyncState.Paused;
}
}
}
private void InternalBeginReceive() {
m_AsyncState |= AsyncState.Pending;
m_Socket.BeginReceive( m_RecvBuffer, 0, m_RecvBuffer.Length, SocketFlags.None, m_OnReceive, m_Socket );
}
public static void Resume() {
m_Paused = false;
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
if ( ns.m_Socket == null ) {
continue;
}
lock ( ns.m_AsyncLock ) {
ns.m_AsyncState &= ~AsyncState.Paused;
try {
if ( ( ns.m_AsyncState & AsyncState.Pending ) == 0 )
ns.InternalBeginReceive();
} catch ( Exception ex ) {
TraceException( ex );
ns.Dispose( false );
}
}
}
}
private IPacketEncoder m_Encoder = null;
public IPacketEncoder PacketEncoder {
@ -515,6 +479,11 @@ namespace Server.Network {
}
}
public void LaunchBrowser( string url ) {
Send( new MessageLocalized( Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", "" ) );
Send( new LaunchBrowser( url ) );
}
public CityInfo[] CityInfo {
get {
return m_CityInfo;
@ -601,14 +570,6 @@ namespace Server.Network {
}
}
public PacketHandler GetHandler( int packetID )
{
if ( ContainerGridLines )
return PacketHandlers.Get6017Handler( packetID );
else
return PacketHandlers.GetHandler( packetID );
}
public virtual void Send( Packet p ) {
if ( m_Socket == null || m_BlockAllPackets ) {
p.OnSend();
@ -642,12 +603,17 @@ namespace Server.Network {
}
if ( gram != null ) {
#if Framework_4_0
m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length );
Send_Start();
#else
try {
m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
#endif
}
} catch ( CapacityExceededException ) {
Console.WriteLine( "Client: {0}: Too much data pending, disconnecting...", this );
@ -670,11 +636,160 @@ namespace Server.Network {
}
}
public static void FlushAll() {
#if Framework_4_0
public void Start() {
m_ReceiveEventArgs = new SocketAsyncEventArgs();
m_ReceiveEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>( Receive_Completion );
m_ReceiveEventArgs.SetBuffer( m_RecvBuffer, 0, m_RecvBuffer.Length );
m_SendEventArgs = new SocketAsyncEventArgs();
m_SendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>( Send_Completion );
m_Running = true;
if ( m_Socket == null || m_Paused ) {
return;
}
Receive_Start();
}
private void Receive_Start()
{
try {
bool result = false;
do {
lock ( m_AsyncLock ) {
if ( ( m_AsyncState & ( AsyncState.Pending | AsyncState.Paused ) ) == 0 ) {
m_AsyncState |= AsyncState.Pending;
result = !m_Socket.ReceiveAsync( m_ReceiveEventArgs );
if ( result )
Receive_Process( m_ReceiveEventArgs );
}
}
} while ( result );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
}
private void Receive_Completion( object sender, SocketAsyncEventArgs e )
{
Receive_Process( e );
if ( !m_Disposing )
Receive_Start();
}
private void Receive_Process( SocketAsyncEventArgs e )
{
int byteCount = e.BytesTransferred;
if ( e.SocketError != SocketError.Success || byteCount <= 0 ) {
Dispose( false );
return;
}
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 );
byte[] buffer = m_RecvBuffer;
if ( m_Encoder != null )
m_Encoder.DecodeIncomingPacket( this, ref buffer, ref byteCount );
lock ( m_Buffer )
m_Buffer.Enqueue( buffer, 0, byteCount );
m_MessagePump.OnReceive( this );
lock ( m_AsyncLock ) {
m_AsyncState &= ~AsyncState.Pending;
}
}
private void Send_Start()
{
try {
bool result = false;
do {
result = !m_Socket.SendAsync( m_SendEventArgs );
if ( result )
Send_Process( m_SendEventArgs );
} while ( result );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
}
private void Send_Completion( object sender, SocketAsyncEventArgs e )
{
Send_Process( e );
if ( m_Disposing )
return;
if ( m_CoalesceSleep >= 0 ) {
Thread.Sleep( m_CoalesceSleep );
}
SendQueue.Gram gram;
lock ( m_SendQueue ) {
gram = m_SendQueue.Dequeue();
}
if ( gram != null ) {
m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length );
Send_Start();
}
}
private void Send_Process( SocketAsyncEventArgs e )
{
int bytes = e.BytesTransferred;
if ( e.SocketError != SocketError.Success || bytes <= 0 ) {
Dispose( false );
return;
}
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 );
}
public static void Pause() {
m_Paused = true;
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
ns.Flush();
lock ( ns.m_AsyncLock ) {
ns.m_AsyncState |= AsyncState.Paused;
}
}
}
public static void Resume() {
m_Paused = false;
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
if ( ns.m_Socket == null ) {
continue;
}
lock ( ns.m_AsyncLock ) {
ns.m_AsyncState &= ~AsyncState.Paused;
if ( ( ns.m_AsyncState & AsyncState.Pending ) == 0 )
ns.Receive_Start();
}
}
}
@ -690,64 +805,14 @@ namespace Server.Network {
}
if ( gram != null ) {
try {
m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket );
return true;
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length );
Send_Start();
}
return false;
}
private static int m_CoalesceSleep = -1;
public static int CoalesceSleep {
get {
return m_CoalesceSleep;
}
set {
m_CoalesceSleep = value;
}
}
private void OnSend( IAsyncResult asyncResult ) {
Socket s = (Socket)asyncResult.AsyncState;
try {
int bytes = s.EndSend( asyncResult );
if ( bytes <= 0 ) {
Dispose( false );
return;
}
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 );
if ( m_CoalesceSleep >= 0 ) {
Thread.Sleep( m_CoalesceSleep );
}
SendQueue.Gram gram;
lock ( m_SendQueue ) {
gram = m_SendQueue.Dequeue();
}
if ( gram != null ) {
try {
s.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
}
} catch ( Exception ){
Dispose( false );
}
}
#else
public void Start() {
m_OnReceive = new AsyncCallback( OnReceive );
@ -771,25 +836,10 @@ namespace Server.Network {
}
}
public void LaunchBrowser( string url ) {
Send( new MessageLocalized( Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", "" ) );
Send( new LaunchBrowser( url ) );
}
private void InternalBeginReceive() {
m_AsyncState |= AsyncState.Pending;
private DateTime m_NextCheckActivity;
public bool CheckAlive() {
if ( m_Socket == null )
return false;
if ( DateTime.Now < m_NextCheckActivity ) {
return true;
}
Console.WriteLine( "Client: {0}: Disconnecting due to inactivity...", this );
Dispose();
return false;
m_Socket.BeginReceive( m_RecvBuffer, 0, m_RecvBuffer.Length, SocketFlags.None, m_OnReceive, m_Socket );
}
private void OnReceive( IAsyncResult asyncResult ) {
@ -831,8 +881,144 @@ namespace Server.Network {
}
}
public void Dispose() {
Dispose( true );
private void OnSend( IAsyncResult asyncResult ) {
Socket s = (Socket)asyncResult.AsyncState;
try {
int bytes = s.EndSend( asyncResult );
if ( bytes <= 0 ) {
Dispose( false );
return;
}
m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 );
if ( m_CoalesceSleep >= 0 ) {
Thread.Sleep( m_CoalesceSleep );
}
SendQueue.Gram gram;
lock ( m_SendQueue ) {
gram = m_SendQueue.Dequeue();
}
if ( gram != null ) {
try {
s.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s );
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
}
} catch ( Exception ){
Dispose( false );
}
}
public static void Pause() {
m_Paused = true;
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
lock ( ns.m_AsyncLock ) {
ns.m_AsyncState |= AsyncState.Paused;
}
}
}
public static void Resume() {
m_Paused = false;
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
if ( ns.m_Socket == null ) {
continue;
}
lock ( ns.m_AsyncLock ) {
ns.m_AsyncState &= ~AsyncState.Paused;
try {
if ( ( ns.m_AsyncState & AsyncState.Pending ) == 0 )
ns.InternalBeginReceive();
} catch ( Exception ex ) {
TraceException( ex );
ns.Dispose( false );
}
}
}
}
public bool Flush() {
if ( m_Socket == null || !m_SendQueue.IsFlushReady ) {
return false;
}
SendQueue.Gram gram;
lock ( m_SendQueue ) {
gram = m_SendQueue.CheckFlushReady();
}
if ( gram != null ) {
try {
m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket );
return true;
} catch ( Exception ex ) {
TraceException( ex );
Dispose( false );
}
}
return false;
}
#endif
public PacketHandler GetHandler( int packetID )
{
if ( ContainerGridLines )
return PacketHandlers.Get6017Handler( packetID );
else
return PacketHandlers.GetHandler( packetID );
}
public static void FlushAll() {
for ( int i = 0; i < m_Instances.Count; ++i ) {
NetState ns = m_Instances[i];
ns.Flush();
}
}
private static int m_CoalesceSleep = -1;
public static int CoalesceSleep {
get {
return m_CoalesceSleep;
}
set {
m_CoalesceSleep = value;
}
}
private DateTime m_NextCheckActivity;
public bool CheckAlive() {
if ( m_Socket == null )
return false;
if ( DateTime.Now < m_NextCheckActivity ) {
return true;
}
Console.WriteLine( "Client: {0}: Disconnecting due to inactivity...", this );
Dispose();
return false;
}
public static void TraceException( Exception ex ) {
@ -856,6 +1042,10 @@ namespace Server.Network {
private bool m_Disposing;
public void Dispose() {
Dispose( true );
}
public virtual void Dispose( bool flush ) {
if ( m_Socket == null || m_Disposing ) {
return;
@ -885,8 +1075,15 @@ namespace Server.Network {
m_Buffer = null;
m_RecvBuffer = null;
#if Framework_4_0
m_ReceiveEventArgs = null;
m_SendEventArgs = null;
#else
m_OnReceive = null;
m_OnSend = null;
#endif
m_Running = false;
m_Disposed.Enqueue( this );