.NET *ASync Socket API
Incomplete, do not use (/d:Framework_4_0) in production.
This commit is contained in:
parent
17b1cccc5e
commit
0afa707b24
2 changed files with 323 additions and 126 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue