• C# SocketAsyncEventArgs Server


    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);
    }


    }
    }

      

  • 相关阅读:
    关于js判断鼠标移入元素的方向--解释
    angularJs的学习笔记(一):angularJs的filter是根据value属性值来过滤的
    虚拟机设置网络连接
    [转载]23个经典JDK设计模式
    Ubuntu 17.04 开启 TCP BBR 拥塞控制算法
    解决DIGITALOCEAN后台被墙的两个方法
    远程访问服务器上的MySQL数据库,发现root远程连接不上
    jsp获取properties配置文件中的属性值
    去除底部“自豪地采用 WordPress”版权信息----最后附最新版的删除方法!!
    改91云linux服务器一键测试脚本(去除上传测试文件代码)
  • 原文地址:https://www.cnblogs.com/LinFx/p/2123670.html
Copyright © 2020-2023  润新知