小弟想做一个简单的异步socket模型。也参考了网上的代码,可一开始就出问题了。封装了一个服务器端类,类中包含服务器端监听套接字,具体代码如下:
class CMiniTcpSvr
    {
        private IPAddress m_LocalIP;
        private Socket _svrSock;
        private ushort _port;
        private static ManualResetEvent myReset = new ManualResetEvent(false);
        Thread m_ListenThread;//负责接受连接的线程
        public CMiniTcpSvr(ushort SvrPort)
        {
            _port = SvrPort;
            m_ListenThread = null;
            //得到服务器本机地址
            IPHostEntry myhost = new IPHostEntry();
            myhost = Dns.GetHostByName("");            String IPString = myhost.AddressList[0].ToString();            m_LocalIP=IPAddress.Parse(IPString);
        }
        /// <summary>
        /// 监听线程,负责接受客户端的连接请求
        /// </summary>
        private void ListenThread()
        {
            while (true)
            {
                myReset.Reset();
                _svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
                myReset.WaitOne();
            }
        }
        public void Start()
        {
            try
            {
                //初始化socket
                _svrSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //绑定端口
                IPEndPoint iep = new IPEndPoint(m_LocalIP, _port);
                _svrSock.Bind(iep);
                //开始监听
                _svrSock.Listen(100);
                //开启线程接收连接请求
                m_ListenThread = new Thread(new ThreadStart(ListenThread));
                m_ListenThread.Start();
            }
            catch (Exception error)
            {
                throw (new ApplicationException(error.Message));
            }
            
            
        }
         ///<summary>
          ///客户端连接处理函数
          ///</summary>
          ///<paramname="iar">欲建立服务器连接的Socket对象</param>
        protected virtual void AcceptConn(IAsyncResult iar)
        {
            
            myReset.Set();
            //接受一个客户端的连接请求
            Socket oldserver = (Socket)iar.AsyncState;
            if (oldserver == null) return;
            Socket client = oldserver.EndAccept(iar);
            //继续接受客户端
            //_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
        }
        public void Stop()
        {
            try
            {
                
                if (_svrSock.Connected)
                {
                    _svrSock.Shutdown(SocketShutdown.Both);
                }
                m_ListenThread.Abort();
                m_ListenThread = null;
                _svrSock.Close();
                _svrSock = null;
                
            }
            catch (Exception error)
            {
                throw (new ApplicationException(error.Message));
            }
            
        }
    }
在外部窗口中调用Start没有出现异常而且检查发现的确是在指定端口上监听了,可当在窗口上调用Stop想关闭服务器的时候出现异常,提示错误代码为:Socket client = oldserver.EndAccept(iar);说对象已经被释放了。
我一开始觉得奇怪,因为我还没做客户端连接呢,只是在服务器端做开始和关闭的动作,怎么就跑到AcceptConn这个函数里面去了呢,这个回调函数不是应该在有客户端连接请求的时候才被调用的么??怎么在执行Stop函数里面的 _svrSock.Close();
即套接字关闭的时候会跑到连接回调函数AcceptConn中去呢???小弟真是郁闷无比,现在问题的焦点就在于:当执行Stop函数的时候怎么会去执行那个连接回调函数的呢????
请各位帮帮忙看看呢!!!

解决方案 »

  1.   

    因为你在客户端stop的时候,是服务器和客户端都关闭了呀!
    _svrSock.Shutdown(SocketShutdown.Both);
    但是后台线程还在监听,你调整一下顺序看看?
      public void Stop()
      {
      try
      {
       
      if (_svrSock.Connected)
      {
      _svrSock.Shutdown(SocketShutdown.Both);
      }
     //将线程先停掉后,再Shutdown和关闭socket连接看看?
      m_ListenThread.Abort();
      m_ListenThread = null;
      _svrSock.Close();
      _svrSock = null;
       
      }
      

  2.   

    if (_svrSock.Connected)
      {
      _svrSock.Shutdown(SocketShutdown.Both);
      }
      m_ListenThread.Abort();
      m_ListenThread = null;
      _svrSock.Close();
      _svrSock = null;
     
    感觉这里的顺序有问题 ,因为当你调用 m_ListenThread.Abort()这个方法的时候,抛出异常,然而后面的代码就不会动行了。你去看一下msdn里面Thread.Abort()这个方法。每次调用都会抛出异常,最好你放到最后面,也可以不用加。当代码运行完时这个线程会自动关闭,前提不要有循环。
      

  3.   

    楼上厉害,
    我一直不太会用.shutdown
    现在才知道shutdownboth是关闭了listen 的那个socket和accpet()返回的那个socket
    是吧?
      

  4.   

    不是的 shutdown只不过是禁用某 Socket 上的发送和接收。并没有关闭socket的连接。多去看看MSDN吧。
      

  5.   

    2楼的兄弟:
    我刚刚试过了,先关闭线程再关闭套接字问题依然存在!
    3楼的兄弟:
    监听线程里的确是有一个循环在的,而且我不希望在关闭监听服务器的时候也必须同时就关闭窗口,故需要用到abort来停止线程的。
    现在我觉得头大的地方在于:_svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);这注册了接受连接的回调函数,不是应该当有连接请求的时候系统才会自动的调用AcceptConn函数的么,我想确定的就是:是不是真的是在系统有连接请求的时候才会自动调用该函数,如果是的话那不是就很奇怪了么,为什么在运行stop的时候还会调用到AcceptConn函数呢???