SocketAsyncEventArgs 连接池
SocketAsyncEventArgsPool
using System;
using System.Net.Sockets;
using System.Collections.Generic;
namespace LinFx.Net.Sockets
{
class SocketAsyncEventArgsPool
{
private readonly Stack<SocketAsyncEventArgs> m_pool;
private readonly object syncLocker = new object();
public SocketAsyncEventArgsPool(int capacity)
{
m_pool = new Stack<SocketAsyncEventArgs>(capacity);
}
public void Push(SocketAsyncEventArgs item)
{
if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); }
lock (syncLocker)
{
if (item.AcceptSocket != null)
item.AcceptSocket = null;
m_pool.Push(item);
}
}
public SocketAsyncEventArgs Pop()
{
lock (syncLocker)
return m_pool.Pop();
}
public int Count { get { return m_pool.Count; } }
}
}
AsyncUserToken
AsyncUserToken
using System; using System.Net.Sockets; using System.Collections.Generic;
namespace LinFx.Net.Sockets { public class AsyncUserToken { Socket m_socket;
public AsyncUserToken() : this(null) { }
public AsyncUserToken(Socket socket) { m_socket = socket; }
public Socket Socket { get { return m_socket; } set { m_socket = value; } }
public ISession Session { get; set; } //public Context Context { get; set; } } }
缓冲区
BufferManager
using System;
using System.Net.Sockets;
using System.Collections.Generic;
namespace LinFx.Net.Sockets
{
internal sealed class BufferManager
{
int m_numBytes; // the total number of bytes controlled by the buffer pool
byte[] m_buffer; // the underlying byte array maintained by the Buffer Manager
Stack<int> m_freeIndexPool; //
int m_currentIndex;
int m_bufferSize;
public BufferManager(int totalBytes, int bufferSize)
{
m_numBytes = totalBytes;
m_currentIndex = 0;
m_bufferSize = bufferSize;
m_freeIndexPool = new Stack<int>();
}
/// <summary>
/// Allocates buffer space used by the buffer pool
/// </summary>
public void InitBuffer()
{
// create one big large buffer and divide that out to each SocketAsyncEventArg object
m_buffer = new byte[m_numBytes];
}
/// <summary>
/// Assigns a buffer from the buffer pool to the specified SocketAsyncEventArgs object
/// </summary>
/// <returns>true if the buffer was successfully set, else false</returns>
public bool SetBuffer(SocketAsyncEventArgs args)
{
if (m_freeIndexPool.Count > 0)
{
args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);
}
else
{
if ((m_numBytes - m_bufferSize) < m_currentIndex)
return false;
args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
m_currentIndex += m_bufferSize;
}
return true;
}
/// <summary>
/// Removes the buffer from a SocketAsyncEventArg object. This frees the buffer back to the
/// buffer pool
/// </summary>
public void FreeBuffer(SocketAsyncEventArgs args)
{
m_freeIndexPool.Push(args.Offset);
args.SetBuffer(null, 0, 0);
}
}
}
Session
Session
using System;
using System.Net;
using System.Net.Sockets;
namespace LinFx.Net.Sockets
{
public interface ISession
{
void Initize(Socket socket);
void ProcessRecv(SocketAsyncEventArgs e);
void ProcessSend(SocketAsyncEventArgs e);
IPEndPoint LocalEndPoint { get; }
IPEndPoint RemoteEndPoint { get; }
event EventHandler<SocketAsyncEventArgs> Closed;
}
public abstract class Session : ISession
{
public Context Context { get; private set; }
public Socket Client { get; private set; }
public IPEndPoint LocalEndPoint { get { return (IPEndPoint)Client.LocalEndPoint; } }
public IPEndPoint RemoteEndPoint { get { return (IPEndPoint)Client.RemoteEndPoint; } }
public event EventHandler<SocketAsyncEventArgs> Closed;
//public virtual void RecvResponse(SocketContext context, byte[] data) { }
//public virtual void RecvResponse(SocketContext context, byte[] data) { }
//public virtual void SendResponse(SocketContext context, byte[] data) { }
//public virtual void SendResponse(SocketContext context, byte[] data) { }
public void Initize(Socket socket)
{
this.Client = socket;
}
public virtual void ProcessRecv(SocketAsyncEventArgs e)
{
if (e.BytesTransferred <= 0 || e.SocketError != SocketError.Success)
{
OnClosed(e);
return;
}
AsyncUserToken token = (AsyncUserToken)e.UserToken;
e.SetBuffer(e.Offset, e.BytesTransferred);
string str = "Hello World";
byte[] buffer = System.Text.Encoding.Default.GetBytes(str);
e.SetBuffer(buffer, 0, buffer.Length);
bool willRaiseEvent = token.Socket.SendAsync(e);
if (!willRaiseEvent)
{
ProcessSend(e);
}
}
public virtual void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
{
OnClosed(e);
return;
}
AsyncUserToken token = (AsyncUserToken)e.UserToken;
bool willRaiseEvent = token.Socket.ReceiveAsync(e);
if (!willRaiseEvent)
{
ProcessRecv(e);
}
}
public virtual void OnClosed(SocketAsyncEventArgs e)
{
if (Closed != null)
Closed(this, e);
}
}
}
这里 Session 只是简单发回 "Hello World"
Server
SocketAsyncEventArgs Server
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;
namespace LinFx.Net.Sockets
{
public class Server
{
int m_nConnection;
BufferManager m_BufferManager; //缓冲区
SocketAsyncEventArgsPool m_ReadWritePool; //连接池
Socket m_sListen; //服务端
Type TSession;
Semaphore m_MaxConnectionSemaphore;
public Server(int n, Type t)
{
this.m_nConnection = n;
this.TSession = t;
}
public void Run()
{
new Thread(new ThreadStart(ListenThreadMethod)).Start();
}
private void ListenThreadMethod()
{
//int bufferSize = Math.Max(AppServer.Config.ReceiveBufferSize, AppServer.Config.SendBufferSize);
//if (bufferSize <= 0)
// bufferSize = 1024 * 8;
int receiveBufferSize = 1024 * 8;
m_BufferManager = new BufferManager(receiveBufferSize * m_nConnection * 2, receiveBufferSize);
m_ReadWritePool = new SocketAsyncEventArgsPool(5);
m_MaxConnectionSemaphore = new Semaphore(5, 5);
m_BufferManager.InitBuffer();
SocketAsyncEventArgs socketEventArg;
for (int i = 0; i < 5; i++)
{
socketEventArg = new SocketAsyncEventArgs();
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
socketEventArg.UserToken = new AsyncUserToken();
m_BufferManager.SetBuffer(socketEventArg);
m_ReadWritePool.Push(socketEventArg);
}
IPAddress ip = IPAddress.Parse("222.222.222.187");
IPEndPoint ipe = new IPEndPoint(ip, 60000);
m_sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_sListen.Bind(ipe);
m_sListen.Listen(50);
PostAccept(null);
}
public void PostAccept(SocketAsyncEventArgs socketEventArgs)
{
if (socketEventArgs == null)
{
socketEventArgs = new SocketAsyncEventArgs();
socketEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketEventArgs_Completed);
}
else
{
socketEventArgs.AcceptSocket = null;
}
m_MaxConnectionSemaphore.WaitOne();
bool willRaiseEvent = m_sListen.AcceptAsync(socketEventArgs);
if (!willRaiseEvent)
{
ProcessAccept(socketEventArgs);
}
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
SocketAsyncEventArgs socketEventArgs = m_ReadWritePool.Pop();
ISession session = Activator.CreateInstance(TSession) as ISession;
session.Closed += new EventHandler<SocketAsyncEventArgs>(Session_Closed);
session.Initize(e.AcceptSocket);
((AsyncUserToken)(socketEventArgs.UserToken)).Socket = e.AcceptSocket;
((AsyncUserToken)(socketEventArgs.UserToken)).Session = session;
bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(socketEventArgs);
if (!willRaiseEvent)
{
session.ProcessRecv(socketEventArgs);
}
PostAccept(e);
}
void socketEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
}
void IO_Completed(object sender, SocketAsyncEventArgs e)
{
AsyncUserToken token = e.UserToken as AsyncUserToken;
ISession session = token.Session;
if (session == null)
return;
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
session.ProcessRecv(e);
break;
case SocketAsyncOperation.Send:
session.ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
void Session_Closed(object sender, SocketAsyncEventArgs e)
{
AsyncUserToken token = e.UserToken as AsyncUserToken;
try
{
token.Socket.Shutdown(SocketShutdown.Send);
}
catch (Exception) { }
token.Socket.Close();
m_MaxConnectionSemaphore.Release();
m_ReadWritePool.Push(e);
}
}
}