Common.TcpLibTcpClientWIOCP

using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;

namespace Common.TcpLib
{

    /// <summary>
    /// 仿IOCP Socket处理客户端
    /// </summary>
    public class TcpClientWIOCP : Common.TcpLib.ITcpClient
    {
        public Socket _clientSocket;
        private string _serverIp;
        private int _port;
        private int _bufferSize = 1024;

        private bool _disposed = false;
        private bool _debug = false;

        private ManualResetEvent connectDone = new ManualResetEvent(false);
        private ManualResetEvent sendDone = new ManualResetEvent(false);

        private object _stopLock = new object();
        private bool _sotpMessage = false;

        #region define delegates
        /// <summary>
        /// 连接上服务器后的事件处理
        /// </summary>
        public _Bgz_OnConnectEventDelegate FOnConnectEventDelegate;

        /// <summary>
        /// 接收服务端发来的数据事件处理
        /// </summary>
        public _Bgz_OnReceiveBeginEventDelegate FOnReceiveBeginEventDelegate;

        /// <summary>
        /// 接收服务端发来的数据事件处理
        /// </summary>
        public _Bgz_OnReceiveingEventDelegate FOnReceiveingEventDelegate;

        /// <summary>
        /// 接收服务端发来的数据事件处理
        /// </summary>
        public _Bgz_OnReceiveEndEventDelegate FOnReceiveEndEventDelegate;

        /// <summary>
        /// 报错信息处理
        /// </summary>
        public _Bgz_OnErrorEventDelegate FOnErrorEventDelegate;
        #endregion

        #region Event
        private void OnConnectEvent(_Bgz_ConnectionState state)
        {
            if (FOnConnectEventDelegate != null) FOnConnectEventDelegate(state);
        }
        private void OnReceiveBeginEvent(_Bgz_ConnectionState state)
        {
            if (FOnReceiveBeginEventDelegate != null) FOnReceiveBeginEventDelegate(state);
        }
        private void OnReceiveingEvent(_Bgz_ConnectionState state)
        {
            if (FOnReceiveingEventDelegate != null) FOnReceiveingEventDelegate(state);
        }
        private void OnReceiveEndEvent(_Bgz_ConnectionState state)
        {
            if (FOnReceiveEndEventDelegate != null) FOnReceiveEndEventDelegate(state);
        }
        private void OnErrorEvent(ErrorType errortype, string msg, _Bgz_ConnectionState state)
        {
            if (FOnErrorEventDelegate != null) FOnErrorEventDelegate(errortype, msg, state);
        }
        #endregion

        #region property

        public int BufferSize
        {
            get
            {
                return _bufferSize;
            }
        }

        public bool Debug
        {
            get
            {
                return _debug;
            }
            set
            {
                _debug = value;
            }
        }
        #endregion

        #region Constructor and Destructor
        public TcpClientWIOCP(string serverIp, int port)
        {
            this._serverIp = serverIp;
            this._port = port;
        }

        public TcpClientWIOCP(string serverIp, int port, int bufferSize)
        {
            this._serverIp = serverIp;
            this._port = port;
            this._bufferSize = bufferSize;
        }

        ~TcpClientWIOCP()
        {
            if (!_disposed)
            {
                Stop();
            }
        }
        #endregion

        #region Private Methods
        private void Dispose()
        {
            if (!_disposed)
            {
                Stop();
                GC.Collect();
                GC.WaitForPendingFinalizers();
                this.FOnConnectEventDelegate = null;
                this.FOnErrorEventDelegate = null;
                this.FOnReceiveBeginEventDelegate = null;
                this.FOnReceiveEndEventDelegate = null;
                this.FOnReceiveingEventDelegate = null;
                _disposed = true;
            }
        }

        private void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndConnect(ar);

                _Bgz_ConnectionState stx = new _Bgz_ConnectionState(client);
                OnConnectEvent(stx);
            }
            catch (Exception ex)
            {
                Stop();
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "ConnectCallback Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
            finally
            {
                connectDone.Set();
            }
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            Socket handler = null;
            try
            {
                _Bgz_ConnectionState stx = ar.AsyncState as _Bgz_ConnectionState;
                handler = stx._conn;

                OnReceiveBeginEvent(stx);

                handler.EndReceive(ar);

                if (handler.Available == 0)
                {
                    Stop();
                    return;
                }

                #region receive
                lock (ar)
                {
                    stx._count = 0;
                    stx._dataStream.SetLength(0);
                    stx._dataStream.Position = 0;

                    if (stx._getonceall)
                    {
                        stx._buffer = new byte[handler.Available];
                        int ret = handler.Receive(stx._buffer, 0, stx._buffer.Length, SocketFlags.None);
                        if (ret > 0)
                        {
                            stx._dataStream.Write(stx._buffer, 0, stx._buffer.Length);
                            stx._count++;
                            OnReceiveingEvent(stx);
                        }
                    }
                    else
                    {
                        while (handler.Available > 0)
                        {
                            if (handler.Available > _bufferSize)
                                stx._buffer = new byte[_bufferSize];
                            else
                                stx._buffer = new byte[handler.Available];
                            int ret = handler.Receive(stx._buffer, 0, stx._buffer.Length, SocketFlags.None);
                            if (ret > 0)
                            {
                                stx._dataStream.Write(stx._buffer, 0, stx._buffer.Length);
                                stx._count++;
                                OnReceiveingEvent(stx);
                            }
                        }
                    }
                }
                #endregion

                OnReceiveEndEvent(stx);

                if (handler.Connected)
                    handler.BeginReceive(stx._buffer, 0, 0, SocketFlags.None, new AsyncCallback(ReceiveCallback), stx);

            }
            catch (Exception ex)
            {
                Stop();
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "ReceiveCallback Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
        }

        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                int bytesSent = client.EndSend(ar);
            }
            catch (Exception ex)
            {
                Stop();
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "Send Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
            finally
            {
                sendDone.Set();
            }
        }
        #endregion

        #region Public Methods

        public void Connect()
        {
            try
            {
                this._clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                connectDone.Reset();
                this._clientSocket.BeginConnect(new IPEndPoint(IPAddress.Parse(_serverIp), _port), new AsyncCallback(ConnectCallback), this._clientSocket);
                connectDone.WaitOne();
                _stopLock = new object();
                _sotpMessage = false;

                _Bgz_ConnectionState stx = new _Bgz_ConnectionState(this._clientSocket);

                _clientSocket.BeginReceive(stx._buffer, 0, 0, SocketFlags.None, new AsyncCallback(ReceiveCallback), stx);
            }
            catch (Exception ex)
            {
                OnErrorEvent(ErrorType.Catch, "连接到远程服务器" + _serverIp + ":" + _port.ToString() + "失败!\r\n" + ex.Message, null);
            }
        }
       
        public void Send(byte[] msg)
        {
            try
            {
                if (_clientSocket.Connected)
                    _clientSocket.Send(msg);
                else
                {
                    _Bgz_ConnectionState stx = new _Bgz_ConnectionState();
                    stx._conn = this._clientSocket;
                    stx._buffer = msg;
                    OnErrorEvent(ErrorType.DisConnect, "未与服务器建立链接,导致发送数据失败!", stx);
                }
            }
            catch (Exception ex)
            {
                Stop();
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "Send Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
        }

        public void SendAsync(byte[] msg)
        {
            try
            {
                if (_clientSocket.Connected == false)
                {
                    throw (new Exception("没有连接客户端不可以发送信息!"));
                }

                byte[] buffer;
                int count = msg.Length;
                int cur = 0;
                while (count > 0)
                {
                    if (count > this._bufferSize)
                        buffer = new byte[_bufferSize];
                    else
                        buffer = new byte[count];

                    for (int i = 0; i < buffer.Length; i++)
                    {
                        buffer[i] = msg[cur + i];
                    }
                    count -= buffer.Length;

                    cur += buffer.Length;

                    _clientSocket.BeginSend(buffer, 0, buffer.Length, 0, new AsyncCallback(SendCallback), _clientSocket);
                    sendDone.WaitOne();
                }
            }
            catch (Exception ex)
            {
                Stop();
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "Send Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
        }

        public void SendAsync(Stream Astream)
        {
            try
            {
                if (_clientSocket.Connected == false)
                {
                    throw (new Exception("没有连接客户端不可以发送信息!"));
                }

                byte[] buffer;
                long count = Astream.Length;
                while (count > 0)
                {
                    if (count > this._bufferSize)
                        buffer = new byte[this._bufferSize];
                    else
                        buffer = new byte[count];

                    Astream.Read(buffer, 0, buffer.Length);
                    count -= buffer.Length;
                    _clientSocket.BeginSend(buffer, 0, buffer.Length, 0, new AsyncCallback(SendCallback), _clientSocket);
                    sendDone.WaitOne();
                }
            }
            catch (Exception ex)
            {
                Stop();
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "Send Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
        }

        public void Stop()
        {
            try
            {
                if (_clientSocket != null)
                {
                    if (_clientSocket.Connected)
                    {
                        _clientSocket.Shutdown(SocketShutdown.Both);
                        _clientSocket.Disconnect(false);
                    }
                    _clientSocket.Close();
                }
                lock (_stopLock)
                {
                    if (!_sotpMessage)
                    {
                        OnErrorEvent(ErrorType.DisConnect, "关闭了与服务器的连接!", null);
                        _sotpMessage = true;
                    }
                }
            }
            catch (Exception ex)
            {
                if (Debug)
                {
                    OnErrorEvent(ErrorType.Catch, "Stop Error![Message]:\r\n" + ex.Message + "[StackTrace]:\r\n" + ex.StackTrace + "\r\n", null);
                }
            }
        }
        #endregion

    }

}

转载于:https://www.cnblogs.com/bigmouthz/archive/2007/11/01/946191.html

结构层次及相互联系 (1)、工作线程:响应连接的IO投递返回并负责投递读请求,并将IO返回结果投递给处理线程,可设定参数决定工作线程数量; (2)、处理线程:处理线程调用回调函数将信息传递给应用层或协议栈,可设定参数决定工作处理数量; (3)、看守线程:响应Accept事件调用AcceptEx,检测连接和心跳超时 ,将信息投递给工作线程,模块仅有一个看守线程。 1. 技术要求 (1)、线程同步:Lock指令、临界段; (2)、主要Socket API:WSASend、WSARecv、AcceptEx、DisconnectEx; (3)、内存管理:连接池(句柄重用)、内存池; (4)、数据0拷贝:通过内置处理线程,上层应用可以避免自建线程池及复制数据的过程。同时提供GBuf内存分配功能,应用层获得分配地址及填充数据之后亦可直接投递给内核/驱动层; (5)、数据顺序同步:同一个连接同时只有一个处理线程响应其IO事件; (6)、IO请求投递:单投递读、多投递写; (7)、0缓冲读投递:可条件编译实现,以适用大规模连接要求。 (8)、超时机制:可设置空连接(连接不发送数据)超时时间以防止DOS攻击,也可设置心跳超时时间防止网络故障导致的现有连接成为虚连接避免耗尽系统资源。 (9)、接口技术:API、回调函数、客户句柄(客户连接句柄)。 (10)、主、被动发送:不使用HASH、MAP及LIST技术,即可提供安全可靠高效的客户连接句柄,以实现服务器端主被动发送数据功能; (11)、PerHandleData的回收不以IO投递的计数器或链表来做依据但仍能安全回收,同时尽量避免在高频的读写操作时做其他无关的操作以提高读写效率。 (12)、处理线程和工作线程有着良好分工界限,繁重的工作交给处理线程完成,工作线程工作量最大限度的减少,仅响应投递返回及读投递的操作; (13)、支持AWE,模块自动识别AWE是否开启(需手动开启),“否”则使用虚拟内存机制。 2. 功能要求 (1)、多IP多端口监听,每个监听可设置不同的回调函数,以高效的区别处理数据 (2)、可设置每秒最大的连接并发量和空连接(连接不发数据)超时时间以防止DOS攻击造成的服务瘫痪、具有心跳处理(防网络异常造成的虚连接)功能 (3)、不加协议的透明传输,可适用广泛的网络通讯环境 (4)、可现实主、被动发送数据,但不会因兼顾主动发送而额外增加降低效率的工作 (5)、内置处理线程,上层应用可不必自建线程池处理数据,所有IO事件按顺序调用回调函数并可以在回调函数内直接处理数据,不必担心多线程造成的接收数据乱序的问题。 (6)、高效率的数据对应关联机制,在初次连接并根据登录数据设置每个连接对应的宿主(Owner)之后,再接收的数据即可立即获得该连接对应的宿主,而不必再做额外的查询工作,并且模块内部采用的是指针关联方式,对于长连接、主动发送的服务器系统而言是高效率的。 (7)、可兼容IPv6 3. 注意事项 因硬件环境和应用环境不同,不合理的配置会出现效率及性能上的问题,因此以下情况出现时,请务必与作者联系以确保获得更好的参数配置: (1)、连接量超过1000个的。超过的应结合具体硬件配置和网络带宽等因素综合设定运行参数。 (2)、带宽使用率超过20%的。工作线程和处理线程数量的设置也是综合考虑数据吞吐量和数据处理负载的因素来设置的,过多的线程会在调度上浪费时间,同时也应该综合考虑线程优先级别来设置工作线程和处理线程数量,两者的设置也不一定能相等。 (3)、服务器端有主动发送需求的、短连接(含网络故障造成的连接断开)出现频率高的。 压力测试工具介绍: 一、 使用G-TcpClient模块 二、 可以设定间隔时间发起大规模长、短连接 三、 可以发起密集数据包,包括即时和定时发送,1M的光纤带宽最大可以达到100K/S(单向)以上,100M本地网最大可以达到10M/S(单向)以上 四、 数据发送仅由一个独立线程但当,每点击一次Connect就创建一个线程根据当前参数发起连接。 五、 测试前提:服务器接收客户端数据后立即原样返回给客户端
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值