以下是我自己封装的一个XTcpListener类.1.当我想断开远程客户端时,无法断开(上网搜过资料,有说在接到NetWorkStream流后,关闭流就可以断掉远程结点)2.当远程客户端断开连接时,我这里总报一些错,比如BeginAcceptTcpClient,BeginRead处....3.收发数据都已正常(网络稳定的情况下)4.请各位高手们帮忙指正~~~飘过的也请留个记号~~~~由于很久没逛CSDN了,分不太多.....
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;namespace XNet
{
    public class XListener
    {
        #region 同步连接设定
        /// <summary>
        /// 设置为同步连接,true为同步,false为异步
        /// </summary>
        private bool _isSync = true;
        /// <summary>
        /// 设置为同步连接,true为同步,false为异步
        /// </summary>
        public bool IsSync
        {
            get { return _isSync; }
            set { _isSync = value; }
        }
        #endregion        #region 是否正在监听
        /// <summary>
        /// 是否正在监听
        /// </summary>
        private bool _isListened = false;
        /// <summary>
        /// 是否正在监听
        /// </summary>
        public bool IsListened
        {
            get { return _isListened; }
            set { _isListened = value; }
        }
        #endregion        #region 挂起队列的最大长度
        /// <summary>
        /// 挂起队列的最大长度
        /// </summary>
        private int _backlog = 50;
        /// <summary>
        /// 挂起队列的最大长度,默认值为50
        /// </summary>
        public int Backlog
        {
            get { return _backlog; }
            set { _backlog = value; }
        }
        #endregion        #region 监听服务对象
        /// <summary>
        /// 监听服务
        /// </summary>
        private TcpListener server = null;
        /// <summary>
        /// 监听服务对象属性访问器
        /// </summary>
        public TcpListener Server
        {
            get { return server; }
            set { server = value; }
        }
        #endregion        #region 缓冲区大小
        private int _bufferLength = 1024;
        /// <summary>
        /// 缓冲区大小
        /// </summary>
        public int BufferLength
        {
            get { return _bufferLength; }
            set { _bufferLength = value; }
        }
        #endregion        #region 构造函数
        /// <summary>
        /// 构造函数,没有参数(基本不起任何作用)
        /// </summary>
        public XListener()
        {
        }
        /// <summary>
        /// 根据已有的TcpListener进行初始化
        /// </summary>
        /// <param name="listener">TcpListener</param>
        public XListener(TcpListener listener)
        {
            server = listener;
        }
        /// <summary>
        /// 监听本地端口(不推荐使用此方法,MSDN说此方法已过时)
        /// </summary>
        /// <param name="port">端口号</param>
        public XListener(int port)
        {
            server = new TcpListener(port);
        }
        /// <summary>
        /// 根据IP地址和Port端口进行初始化
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        public XListener(IPAddress ipAddress, int port)
        {
            server = new TcpListener(ipAddress, port);
        }
        /// <summary>
        /// 根据本地结点进行初始化
        /// </summary>
        /// <param name="iep">本地结点 IPEndPoint类型</param>
        public XListener(IPEndPoint iep)
        {
            server = new TcpListener(iep);
        }
        #endregion        

解决方案 »

  1.   


    #region 开始监听
            /// <summary>
            /// 开始监听服务,默认的挂起队列最大长度为50,可以通过Backlog属性修改或使用本方法的重载方法
            /// </summary>
            public void Start()
            {
                Start(_backlog);
            }
            /// <summary>
            /// 开始监听服务
            /// </summary>
            /// <param name="backlog">挂起队列的最大长度</param>
            public void Start(int backlog)
            {
                if (server == null)
                {
                    throw new Exception("监听服务对象为空,不能进行监听服务");
                }
                else if (_isListened)
                {
                    throw new Exception("系统已经开始监听");
                }
                else
                {
                    try
                    {
                        server.Start(backlog);
                        _isListened = true;
                        if (_isSync)
                        {
                            SyncAccept();
                        }
                        else
                        {
                            server.BeginAcceptTcpClient(new AsyncCallback(OnAsyncAcceptTcpClient), null);
                        }
                    }
                    catch (System.Exception ex)
                    {
                        throw new Exception(ex.Message);
                    }
                }
            }
            #endregion        #region 字节计数
            private long _receiveBytes = 0;
            /// <summary>
            /// 收到字节数
            /// </summary>
            public long ReceiveBytes
            {
                get { return _receiveBytes; }
                set { _receiveBytes = value; }
            }
            #endregion        #region 当监听到客户连接时,是否对客户端发送数据及发送什么数据
            /// <summary>
            /// 当监听到客户连接时,是否对客户端发送数据
            /// </summary>
            public bool IsAutoResponse = false;
            /// <summary>
            /// 当监听到客户连接时,对客户端发送的数据(UTF-8编码格式)
            /// </summary>
            public string IsAutoResponseData = "";
            #endregion        #region 同步方式处理接收的连接及收到的数据
            /// <summary>
            /// 同步阻塞接收连接
            /// </summary>
            private void SyncAccept()
            {
                while (true)
                {
                    _isListened = true;
                    TcpClient client = server.AcceptTcpClient();
                    //触发有客户端连接上来的事件
                    if (client != null)
                    {
                        if (OnAcceptClientEvent != null)
                        {
                            IPEndPoint iep = (IPEndPoint)client.Client.RemoteEndPoint;
                            IPEndPoint localPoint = (IPEndPoint)client.Client.LocalEndPoint;
                            AcceptClientArgs e = new AcceptClientArgs(iep.Address, iep.Port, DateTime.Now, localPoint.Address, localPoint.Port);
                            OnAcceptClientEvent(this, e);
                        }
                    }                //放入线程池处理接收到的连接
                    ThreadPool.QueueUserWorkItem(new WaitCallback(SyncProcessTcpClient), client);
                }
            }
            /// <summary>
            /// 同步方式处理接收到的数据
            /// </summary>
            /// <param name="obj"></param>
            private void SyncProcessTcpClient(object obj)
            {
                TcpClient client = obj as TcpClient;
                NetworkStream ns = client.GetStream();
                try
                {
                    if (ns.CanRead)
                    {
                        byte[] buffer = new byte[_bufferLength];
                        int length = ns.Read(buffer, 0, buffer.Length);
                        //对连接上的客户端发送数据
                        if (ns.CanWrite)
                            if (IsAutoResponse)
                            {
                                byte[] data = Encoding.UTF8.GetBytes("[UTF-8] " + IsAutoResponseData);
                                ns.Write(data, 0, data.Length);
                            }                    ns.Close();
                        Array.Resize(ref buffer, length);
                        //收到数据字节计数
                        _receiveBytes += buffer.Length;                    //处理接收到的数据
                        if (OnMessageArrivalEvent != null)
                        {
                            IPEndPoint iep = (IPEndPoint)client.Client.RemoteEndPoint;
                            IPEndPoint localPoint = (IPEndPoint)client.Client.LocalEndPoint;
                            MessageEventArgs e = new MessageEventArgs(iep.Address, iep.Port, buffer, DateTime.Now, localPoint.Address, localPoint.Port);                        OnMessageArrivalEvent(this, e);
                        }                    client.Close();
                    }
                }
                catch (System.Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
            #endregion        #region 异步接收连接并处理缓冲区数据
            /// <summary>
            /// 异步处理接收到的连接
            /// </summary>
            /// <param name="iar"></param>
            private void OnAsyncAcceptTcpClient(IAsyncResult iar)
            {
                if (!_isListened)
                {
                    if (server != null)
                        throw new Exception("监听服务未开启,无法处理接收到的异步连接");
                }
                else
                {
                    try
                    {
                        if (server == null)
                            return;
                        TcpClient client = server.EndAcceptTcpClient(iar);
                        //触发有客户端连接上来的事件
                        if (client != null)
                        {
                            if (OnAcceptClientEvent != null)
                            {
                                IPEndPoint iep = (IPEndPoint)client.Client.RemoteEndPoint;
                                IPEndPoint localPoint = (IPEndPoint)client.Client.LocalEndPoint;
                                AcceptClientArgs e = new AcceptClientArgs(iep.Address, iep.Port, DateTime.Now, localPoint.Address, localPoint.Port);
                                OnAcceptClientEvent(this, e);
                            }
                        }                    //开始异步接收连接
                        server.BeginAcceptTcpClient(new AsyncCallback(OnAsyncAcceptTcpClient), null);                    NetworkStream ns = client.GetStream();
                        if (ns.CanRead)
                        {
                            byte[] buffer = new byte[_bufferLength];
                            ns.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnAsyncRead), new object[] { client, ns, buffer });
                        }
                    }
                    catch (System.NullReferenceException nrex)
                    {
                        Console.WriteLine("连接已断开");
                    }
                    catch (System.Exception ex)
                    {
                        throw new Exception(ex.Message);
                    }
                }
            }
            /// <summary>
            /// 异步读取数据并处理接收到的数据
            /// </summary>
            /// <param name="iar"></param>
            private void OnAsyncRead(IAsyncResult iar)
            {
                object[] obj = iar.AsyncState as object[];
                TcpClient client = obj[0] as TcpClient;
                NetworkStream ns = obj[1] as NetworkStream;
                byte[] buffer = obj[2] as byte[];
                try
                {
                    if (ns.CanRead)
                    {
                        int length = ns.EndRead(iar);
                        Array.Resize(ref buffer, length);
                        //收到数据字节计数
                        _receiveBytes += buffer.Length;
                    }
                    //对连接上的客户端发送数据
                    if (ns.CanWrite)
                    {
                        if (IsAutoResponse)
                        {
                            byte[] data = Encoding.UTF8.GetBytes("[UTF-8] " + IsAutoResponseData);
                            ns.Write(data, 0, data.Length);
                        }
                    }
                    if (server == null || _isListened == false)
                        return;                byte[] buffer2 = new byte[_bufferLength];
                    if (ns.CanRead)
                    {
                        ns.BeginRead(buffer2, 0, buffer.Length, new AsyncCallback(OnAsyncRead), new object[] { client, ns, buffer2 });
                    }
                    //处理接收到的数据
                    if (OnMessageArrivalEvent != null)
                    {
                        IPEndPoint iep = (IPEndPoint)client.Client.RemoteEndPoint;
                        IPEndPoint localPoint = (IPEndPoint)client.Client.LocalEndPoint;
                        MessageEventArgs e = new MessageEventArgs(iep.Address, iep.Port, buffer, DateTime.Now, localPoint.Address, localPoint.Port);                    OnMessageArrivalEvent(this, e);
                    }
                }
                catch (System.Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
            #endregion        #region 停止监听
            /// <summary>
            /// 停止监听服务
            /// </summary>
            public void Stop()
            {
                try
                {
                    //关闭现有的连接
                    server.Server.Shutdown(SocketShutdown.Both);
                    server.Server.Close();
                    server.Stop();
                    _isListened = false;
                    IsAutoResponse = false;
                }
                catch (System.Exception ex)
                {
                    throw new Exception(ex.Message);
                }
                finally
                {
                    server = null;
                }
            }
            #endregion        /// <summary>
            /// 数据到达事件
            /// </summary>
            public event EventHandler<MessageEventArgs> OnMessageArrivalEvent = null;
            /// <summary>
            /// 监听到有客户端连接
            /// </summary>
            public event EventHandler<AcceptClientArgs> OnAcceptClientEvent = null;        //public event EventHandler<string> OnException = null;
        }}
      

  2.   

    以上是封装的XTcpListener类,接下来有两个类,是我代码里面封装的事件要用的类using System;
    using System.Collections.Generic;
    using System.Text;namespace XNet
    {
        public class ExceptionArgs : EventArgs
        {
            /// <summary>
            /// 异常发生时间
            /// </summary>
            public DateTime ExceptionTime = DateTime.Now;
            /// <summary>
            /// 异常对象
            /// </summary>
            public Exception ex = null;
            /// <summary>
            /// 异常类
            /// </summary>
            /// <param name="ExceptionTime"></param>
            /// <param name="exception"></param>
            public ExceptionArgs(System.Exception exception)
            {
                this.ex = exception;
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Text;namespace XNet
    {
        /// <summary>
        /// 网络连接收到的数据
        /// </summary>
        public class MessageEventArgs : EventArgs
        {
            private System.Net.IPAddress _ip;
            private int _port;
            private byte[] _data;
            private DateTime _dt;
            private System.Net.IPAddress _localIp;
            private int _localPort;        /// <summary>
            /// 远程IP地址
            /// </summary>
            public System.Net.IPAddress RemoteIP
            {
                get { return _ip; }
                set { _ip = value; }
            }
            /// <summary>
            /// 远程端口号
            /// </summary>
            public int RemotePort
            {
                get { return _port; }
                set { _port = value; }
            }
            /// <summary>
            /// 缓冲区数据
            /// </summary>
            public byte[] Data
            {
                get { return _data; }
                set { _data = value; }
            }
            /// <summary>
            /// 数据到达时间
            /// </summary>
            public DateTime ReceiveTime
            {
                get { return _dt; }
                set { _dt = value; }
            }
            /// <summary>
            /// 本地IP
            /// </summary>
            public System.Net.IPAddress LocalIP
            {
                get { return _localIp; }
                set { _localIp = value; }
            }
            /// <summary>
            /// 本地端口
            /// </summary>
            public int LocalPort
            {
                get { return _localPort; }
                set { _localPort = value; }
            }        /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="ip">IP地址</param>
            /// <param name="port">端口号</param>
            /// <param name="data">缓冲区的字节数组</param>
            /// <param name="dt">数据到达时间</param>
            /// <param name="localIp">本地IP地址</param>
            /// <param name="localPort">本地端口</param>
            public MessageEventArgs(System.Net.IPAddress remoteIp, int remotePort, byte[] data, DateTime dt, System.Net.IPAddress localIp, int localPort)
            {
                _ip = remoteIp;
                _port = remotePort;
                _data = data;
                _dt = dt;
                _localIp = localIp;
                _localPort = localPort;
            }
        }
    }
      

  3.   

    我的一点解决思路:
    当时我在做tcp通讯的时候也遇到了类似的问题,后来我采用了下面一些手段加以解决:
    1、对tcpclient再外包一层类,里面附加了该连接的最后一次与我服务端通讯时间,产生的交互数据队列,以及处理逻辑等,这样Tcplistener层只负责接收连接,然后就生成我的外包一层的对象,并持有住。外包对象的业务处理封装在内部,全部是异步委托方式进行。
    2在Tcplistener层内置一个timer,定时扫描所有的tcpclient外包对象,检查最后一次访问时间是否超过某一阙值,超过了就检查该连接是否已经失活,一旦失活就关闭其基础socket和流,并不再持有该外包对象(让其被GC自动回收。)代码如下:
    try
    {
    Socket.Select(LinkBuff_Copy, null, null, 10000);
    }
    catch
    {
        LinkBuff_Copy.Clear();
    }
    finally
    {
     if (LinkBuff_Copy.Count > 0)
    {
    //一一释放tcpclient,并从正式连接缓冲中移除失活对象
    }
    }
    呵呵,我的思路希望对你有所帮助。
      

  4.   

    没人了么? CSDN 现在不会就这么冷了下去吧~