c# Socket异步接收数据

异步接受数据的问题,对于大量的数据流,考虑异步操作是必须的。
  关于异步接受,牵扯的知识点非常多,从线程,到锁,到流,到回调等等。这里一一讲起来就比较复杂了,我还是挑一些说说就罢了。
  先说思路:
  
  1:创建Socket。
  2:创建Queue实现整个过程的回滚与接收。
  3:创建ReaderWriterLock实现锁。
  4:创建ManualResetEvent实现事件的自动激发,主要作为数据接收后下次再继续接受时激发。
  5:关闭Socket.

  这个类来自codeproject上的牛人,先贴上来:
  

    class SocketStateObject
    {
        private Socket _workSocket;
        public byte[] buffer;
        public StringBuilder sb = new StringBuilder();
        public bool complete;
        public const int BUFFER_SIZE = 1024;

        public SocketStateObject(Socket _socket)
        {
            buffer = new byte[BUFFER_SIZE];
            complete = false;
            _workSocket = _socket;
        }

        public Socket WorkSocket
        {
            get { return _workSocket; }
        }
    }

    class AsynchSocketManager
    {

        private const int SleepPeriod = 10; // sleep for 10 miliseconds

        private Queue TransmitQueue = new Queue();
        private Queue ReceiveQueue = new Queue();
        private ReaderWriterLock TransmitLock = new ReaderWriterLock();
        private ReaderWriterLock ReceiveLock = new ReaderWriterLock();
        private bool _IsConnected = false;
        private Socket _Socket;
        //private TcpClient client;
        
        private ManualResetEvent ReaderDone = new ManualResetEvent(false);
        private ManualResetEvent WriterDone = new ManualResetEvent(false);
        private ManualResetEvent StopEvent = new ManualResetEvent(false);
        private AutoResetEvent DataReady = new AutoResetEvent(false);

        private int MyId;
        static private int Id;
        private long StartTime;

        public delegate void OnReceiveDelegate(int id, string msg);
        public delegate void OnConnectDelegate(int id, bool bSuccess);
        public delegate void OnDisconnectDelegate(int id);

        public OnReceiveDelegate OnReceive;
        public OnConnectDelegate OnConnect;
        public OnDisconnectDelegate OnDisconnect;

        public AsynchSocketManager(    OnConnectDelegate OnConnect, 
            OnDisconnectDelegate OnDisconnect,
            OnReceiveDelegate OnReceive)
        {
            // copy the delegates
            this.OnReceive = OnReceive;
            this.OnConnect = OnConnect;
            this.OnDisconnect = OnDisconnect;

            Id++; // increment our "global" id - could use 'real' quid's here...
            MyId = Id; // save the value locally
            StartTime = DateTime.Now.Ticks;
        }


        ~ AsynchSocketManager()
        {
            Disconnect();
        }

        public int SessionID
        {
            get { return MyId; }
        }

        public int Connect(string hostName, int serviceport)
        {
            if (_IsConnected)
                return -1; //'no need to do anything once connected

            // resolve...
            IPHostEntry hostEntry = Dns.Resolve(hostName);
            if ( hostEntry != null )
            {
                // create an end-point for the first address...
                IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], serviceport);

                // create a tcp client...
                TcpClient client = new TcpClient();

                try
                {
                    client.Connect(endPoint);
                }
                catch (Exception ex)
                {
                    ex = ex;
                    OnConnect(MyId, false);
                    return -1;
                }

                _Socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
                try
                {
                    _Socket.Connect( endPoint );
                    string gStr = "GET / HTTP/1.1\r\nHost: "+hostName+"\r\nConnection: Close\r\n\r\n";
                    byte[] bs = Encoding.ASCII.GetBytes(gStr);//把字符串编码为字节
                    _Socket.Send(bs, bs.Length, 0);//发送信息


                }
                catch (Exception ex)
                {
                    ex = ex;
                    OnConnect(MyId, false);
                    return -1;
                }

                OnConnect(MyId, true);

                ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveThreadEntryPoint));
                ThreadPool.QueueUserWorkItem(new WaitCallback(SendThreadEntryPoint));
                _IsConnected = true;

                // return this unique id
                return MyId;
            }
            else
            {
                return -1;
            }
        }

//        private void ProcessConnection(TcpClient client)
//        {
//            // set it up...
//            _client = client;
//
//            // get the socket through reflection...
//            PropertyInfo propertyInfo = _client.GetType().GetProperty("Client", BindingFlags.Instance | BindingFlags.NonPublic);
//            if (propertyInfo == null)
//                return;
//
//            Socket = (Socket)propertyInfo.GetValue(_client, null);
//
//            // spin up the threads...
//            //add the two threads for Receive and transmit
//            ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveThreadEntryPoint));
//            ThreadPool.QueueUserWorkItem(new WaitCallback(SendThreadEntryPoint));
//            _isConnected = true;
//        }


        public bool IsConnected
        {
            get { return (_Socket == null ? false : _Socket.Connected); }
        }

        public void Disconnect()
        {
            if (IsConnected)
            {
                _IsConnected = false;

                // signal the threads to end
                StopEvent.Set();

                // wait for workers to spin down
                //WaitHandle[] waithandles;

                //waithandles = new WaitHandle[2];
                //waithandles[0] = _readerDone;
                //waithandles[1] = _writerDone;

                // wait for those guys to stop
                //WaitHandle.WaitAll(waithandles, -1, false);

                // now kill the socket
                if (_Socket != null)
                {
                    _Socket.Close();
                }
                OnDisconnect(MyId);
            }
        }

        public void SendMessage(string message)
        {
            // queue it...
            TransmitLock.AcquireWriterLock(-1);
            try
            {
                TransmitQueue.Enqueue(message);
            }
            catch {}
            finally { TransmitLock.ReleaseWriterLock(); }

            // signal that data was sent
            DataReady.Set();
        }

        public void ReceiveThreadEntryPoint(object state)
        {
            try
            {
                // loop...
                while( true )
                {
                    WaitHandle[] handles = new WaitHandle[1];
                    handles[0] = StopEvent;

                    if ( _Socket != null && _Socket.Connected )
                    {
                        // not disconnected
                        try
                        {
                            // start the recieve operation
                            System.IAsyncResult iar;
                            SocketStateObject so2 = new SocketStateObject(_Socket);
                            iar = _Socket.BeginReceive(so2.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(AsynchReadCallback), so2);

                            if( WaitHandle.WaitAny(handles) == 0 )
                            {
                                break;
                            }
                        }
                        catch {}
                    }
                }
            }
            catch {}
        }

        public void SendThreadEntryPoint(object state)
        {
            try
            {
                Queue workQueue = new Queue();

                // loop...
                while( true )
                {
                    WaitHandle[] handles = new WaitHandle[2];
                    handles[0] = StopEvent;
                    handles[1] = DataReady;

                    if( WaitHandle.WaitAny(handles) == 0 )
                    {
                        break;
                    }
                    else if (_Socket != null && _Socket.Connected)
                    {
                        // not disconnected
                        // go through the queue...
                        TransmitLock.AcquireWriterLock(-1);
                        try
                        {
                            workQueue.Clear();
                            foreach( string message in TransmitQueue)
                            {
                                workQueue.Enqueue(message);
                            }
                            TransmitQueue.Clear();
                        }
                        catch {}
                        finally 
                        {
                            TransmitLock.ReleaseWriterLock();
                        }

                        // loop the outbound messages...
                        foreach( string message in workQueue )
                        {
                            SocketStateObject so2 = new SocketStateObject(_Socket);
                            byte[] buff = Encoding.ASCII.GetBytes(message);

                            // send it...
                            System.IAsyncResult iar;
                            iar = _Socket.BeginSend(buff, 0, buff.Length, 0, new AsyncCallback(AsynchSendCallback), so2);
                        }
                    }
                }
            }
            catch {}
        }

        public void AsynchSendCallback(System.IAsyncResult ar)
        {
            SocketStateObject so = (SocketStateObject)ar.AsyncState;
            Socket s = so.WorkSocket;

            try
            {
                // sanity check
                if (s == null || !s.Connected) return;
                int send = s.EndSend(ar);
            }
            catch {}
        }

        private void AsynchReadCallback(System.IAsyncResult ar)
        {
            SocketStateObject so = (SocketStateObject)ar.AsyncState;
            Socket s = so.WorkSocket;

            try
            {
                // sanity check
                if (s == null || !s.Connected) return;
                int read = s.EndReceive(ar);
                if (read > 0)
                {
                    string msg = Encoding.ASCII.GetString(so.buffer, 0, read);
                    if (OnReceive != null)
                    {
                        OnReceive(MyId, msg);
                    }

                    // and start recieving more
                    s.BeginReceive(so.buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(AsynchReadCallback), so);
                }
            }
            catch {}
        }
    }

  
  比较复杂。
  在使用的时候:
        protected void HandleInput(int id, string msg)
        {
            if( !IsMainThread() )
            {
                object [] args = new object[2];

                args[0] = id;
                args[1] = msg;
                Invoke( new HandleInputDelegate(HandleInput), args );
            }
            else
            {
                tbOutput.Text += msg;
                tbOutput.SelectionStart = tbOutput.TextLength;
            }
        }

        private void ThreadFunction()
        {
            socketMgr = new AsynchSocketLib.AsynchSocketManager( new AsynchSocketLib.AsynchSocketManager.OnConnectDelegate(HandleInitiateConnection), new AsynchSocketLib.AsynchSocketManager.OnDisconnectDelegate(HandleDisconnect), new AsynchSocketLib.AsynchSocketManager.OnReceiveDelegate(HandleInput) );

            // and start it up
            cmdConnect.Enabled = false;
            socketMgr.Connect( tbHostAddress.Text, Convert.ToInt32(tbHostPort.Text) );
        }



  异步接受就这样,比较复杂。慢慢体会,消化。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值